001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.serializer;
018
019import static org.apache.juneau.collections.JsonMap.*;
020import static org.apache.juneau.common.utils.Utils.*;
021
022import java.io.*;
023import java.lang.annotation.*;
024import java.util.*;
025import java.util.function.*;
026
027import org.apache.juneau.*;
028import org.apache.juneau.annotation.*;
029import org.apache.juneau.collections.*;
030import org.apache.juneau.internal.*;
031import org.apache.juneau.soap.*;
032import org.apache.juneau.utils.*;
033
034/**
035 * Parent class for all Juneau serializers.
036 *
037 * <h5 class='topic'>Description</h5>
038 * <p>
039 * Base serializer class that serves as the parent class for all serializers.
040 *
041 * <p>
042 * The purpose of this class is:
043 * <ul>
044 *    <li>Maintain a read-only configuration state of a serializer.
045 *    <li>Create session objects used for serializing POJOs (i.e. {@link SerializerSession}).
046 *    <li>Provide convenience methods for serializing POJOs without having to construct session objects.
047 * </ul>
048 *
049 * <p>
050 * Subclasses should (but are not required to) extend directly from {@link OutputStreamSerializer} or {@link WriterSerializer} depending on
051 * whether it's a stream or character based serializer.
052 *
053 * <p>
054 * Subclasses must implement parsing via one of the following methods:
055 * <ul class='javatree'>
056 *    <li class='jmp'>{@link #doSerialize(SerializerSession, SerializerPipe, Object)}
057 *    <li class='jmp'>{@link SerializerSession#doSerialize(SerializerPipe, Object)}
058 * </ul>
059 * <br>
060 *
061 * <h5 class='section'>Notes:</h5><ul>
062 *    <li class='note'>This class is thread safe and reusable.
063 * </ul>
064 *
065 * <h5 class='section'>See Also:</h5><ul>
066 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/SerializersAndParsers">Serializers and Parsers</a>
067
068 * </ul>
069 */
070public class Serializer extends BeanTraverseContext {
071
072   //-------------------------------------------------------------------------------------------------------------------
073   // Static
074   //-------------------------------------------------------------------------------------------------------------------
075
076   /**
077    * Creates a new builder for this object.
078    *
079    * @return A new builder.
080    */
081   public static Builder create() {
082      return new Builder();
083   }
084
085   /**
086    * Represents no Serializer.
087    */
088   public static abstract class Null extends Serializer {
089      private Null(Builder builder) {
090         super(builder);
091      }
092   }
093
094   /**
095    * Instantiates a builder of the specified serializer class.
096    *
097    * <p>
098    * Looks for a public static method called <c>create</c> that returns an object that can be passed into a public
099    * or protected constructor of the class.
100    *
101    * @param c The builder to create.
102    * @return A new builder.
103    */
104   public static Builder createSerializerBuilder(Class<? extends Serializer> c) {
105      return (Builder)Context.createBuilder(c);
106   }
107
108   //-------------------------------------------------------------------------------------------------------------------
109   // Builder
110   //-------------------------------------------------------------------------------------------------------------------
111
112   /**
113    * Builder class.
114    */
115   public static class Builder extends BeanTraverseContext.Builder {
116
117      boolean addBeanTypes, addRootType, keepNullProperties, sortCollections, sortMaps, trimEmptyCollections,
118         trimEmptyMaps, trimStrings;
119      String produces, accept;
120      UriContext uriContext;
121      UriRelativity uriRelativity;
122      UriResolution uriResolution;
123      Class<? extends SerializerListener> listener;
124
125      /**
126       * Constructor, default settings.
127       */
128      protected Builder() {
129         produces = null;
130         accept = null;
131         addBeanTypes = env("Serializer.addBeanTypes", false);
132         addRootType = env("Serializer.addRootType", false);
133         keepNullProperties = env("Serializer.keepNullProperties", false);
134         sortCollections = env("Serializer.sortCollections", false);
135         sortMaps = env("Serializer.sortMaps", false);
136         trimEmptyCollections = env("Serializer.trimEmptyCollections", false);
137         trimEmptyMaps = env("Serializer.trimEmptyMaps", false);
138         trimStrings = env("Serializer.trimStrings", false);
139         uriContext = UriContext.DEFAULT;
140         uriRelativity = UriRelativity.RESOURCE;
141         uriResolution = UriResolution.NONE;
142         listener = null;
143      }
144
145      /**
146       * Copy constructor.
147       *
148       * @param copyFrom The bean to copy from.
149       */
150      protected Builder(Serializer copyFrom) {
151         super(copyFrom);
152         produces = copyFrom.produces;
153         accept = copyFrom.accept;
154         addBeanTypes = copyFrom.addBeanTypes;
155         addRootType = copyFrom.addRootType;
156         keepNullProperties = copyFrom.keepNullProperties;
157         sortCollections = copyFrom.sortCollections;
158         sortMaps = copyFrom.sortMaps;
159         trimEmptyCollections = copyFrom.trimEmptyCollections;
160         trimEmptyMaps = copyFrom.trimEmptyMaps;
161         trimStrings = copyFrom.trimStrings;
162         uriContext = copyFrom.uriContext;
163         uriRelativity = copyFrom.uriRelativity;
164         uriResolution = copyFrom.uriResolution;
165         listener = copyFrom.listener;
166      }
167
168      /**
169       * Copy constructor.
170       *
171       * @param copyFrom The builder to copy from.
172       */
173      protected Builder(Builder copyFrom) {
174         super(copyFrom);
175         produces = copyFrom.produces;
176         accept = copyFrom.accept;
177         addBeanTypes = copyFrom.addBeanTypes;
178         addRootType = copyFrom.addRootType;
179         keepNullProperties = copyFrom.keepNullProperties;
180         sortCollections = copyFrom.sortCollections;
181         sortMaps = copyFrom.sortMaps;
182         trimEmptyCollections = copyFrom.trimEmptyCollections;
183         trimEmptyMaps = copyFrom.trimEmptyMaps;
184         trimStrings = copyFrom.trimStrings;
185         uriContext = copyFrom.uriContext;
186         uriRelativity = copyFrom.uriRelativity;
187         uriResolution = copyFrom.uriResolution;
188         listener = copyFrom.listener;
189      }
190
191      @Override /* Context.Builder */
192      public Builder copy() {
193         return new Builder(this);
194      }
195
196      @Override /* Context.Builder */
197      public Serializer build() {
198         return build(Serializer.class);
199      }
200
201      @Override /* Context.Builder */
202      public HashKey hashKey() {
203         return HashKey.of(
204            super.hashKey(),
205            produces,
206            accept,
207            addBeanTypes,
208            addRootType,
209            keepNullProperties,
210            sortCollections,
211            sortMaps,
212            trimEmptyCollections,
213            trimEmptyMaps,
214            trimStrings,
215            uriContext,
216            uriRelativity,
217            uriResolution,
218            listener
219         );
220      }
221
222      //-----------------------------------------------------------------------------------------------------------------
223      // Properties
224      //-----------------------------------------------------------------------------------------------------------------
225
226      /**
227       * Specifies the media type that this serializer produces.
228       *
229       * @param value The value for this setting.
230       * @return This object.
231       */
232      public Builder produces(String value) {
233         this.produces = value;
234         return this;
235      }
236
237      /**
238       * Returns the current value for the 'produces' property.
239       *
240       * @return The current value for the 'produces' property.
241       */
242      public String getProduces() {
243         return produces;
244      }
245
246      /**
247       *    Specifies the accept media types that the serializer can handle.
248       *
249       *    <p>
250       *    Can contain meta-characters per the <c>media-type</c> specification of <a class="doclink" href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html">RFC2616/14.1</a>
251       *    <p>
252       *    If empty, then assumes the only media type supported is <c>produces</c>.
253       *    <p>
254       *    For example, if this serializer produces <js>"application/json"</js> but should handle media types of
255       *    <js>"application/json"</js> and <js>"text/json"</js>, then the arguments should be:
256       *    <p class='bjava'>
257       *       <jv>builder</jv>.produces(<js>"application/json"</js>);
258       *       <jv>builder</jv>.accept(<js>"application/json,text/json"</js>);
259       *    </p>
260       * <p>
261       * The accept value can also contain q-values.
262       *
263       * @param value The value for this setting.
264       * @return This object.
265       */
266      public Builder accept(String value) {
267         this.accept = value;
268         return this;
269      }
270
271      /**
272       * Returns the current value for the 'accept' property.
273       *
274       * @return The current value for the 'accept' property.
275       */
276      public String getAccept() {
277         return accept;
278      }
279
280      /**
281       * Add <js>"_type"</js> properties when needed.
282       *
283       * <p>
284       * When enabled, <js>"_type"</js> properties will be added to beans if their type cannot be inferred
285       * through reflection.
286       *
287       * <p>
288       * This is used to recreate the correct objects during parsing if the object types cannot be inferred.
289       * <br>For example, when serializing a <c>Map&lt;String,Object&gt;</c> field where the bean class cannot be determined from
290       * the type of the values.
291       *
292       * <p>
293       * Note the differences between the following settings:
294       * <ul class='javatree'>
295       *    <li class='jf'>{@link #addRootType()} - Affects whether <js>'_type'</js> is added to root node.
296       *    <li class='jf'>{@link #addBeanTypes()} - Affects whether <js>'_type'</js> is added to any nodes.
297       * </ul>
298       *
299       * <h5 class='section'>Example:</h5>
300       * <p class='bjava'>
301       *    <jc>// Create a serializer that adds _type to nodes.</jc>
302       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
303       *       .<jsm>create</jsm>()
304       *       .addBeanTypes()
305       *       .build();
306       *
307       *    <jc>// Our map of beans to serialize.</jc>
308       *    <ja>@Bean</ja>(typeName=<js>"mybean"</js>)
309       *    <jk>public class</jk> MyBean {
310       *       <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>;
311       *    }
312       *    JsonMap <jv>myMap</jv> = JsonMap.of(<js>"foo"</js>, <jk>new</jk> MyBean());
313       *
314       *    <jc>// Will contain:  {"foo":{"_type":"mybean","foo":"bar"}}</jc>
315       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jv>myMap</jv>);
316       * </p>
317       *
318       * @return This object.
319       */
320      public Builder addBeanTypes() {
321         return addBeanTypes(true);
322      }
323
324      /**
325       * Same as {@link #addBeanTypes()} but allows you to explicitly specify the value.
326       *
327       * @param value The value for this setting.
328       * @return This object.
329       */
330      public Builder addBeanTypes(boolean value) {
331         addBeanTypes = value;
332         return this;
333      }
334
335      /**
336       * Add type attribute to root nodes.
337       *
338       * <p>
339       * When enabled, <js>"_type"</js> properties will be added to top-level beans.
340       *
341       * <p>
342       * When disabled, it is assumed that the parser knows the exact Java POJO type being parsed, and therefore top-level
343       * type information that might normally be included to determine the data type will not be serialized.
344       *
345       * <p>
346       * For example, when serializing a top-level POJO with a {@link Bean#typeName() @Bean(typeName)} value, a
347       * <js>'_type'</js> attribute will only be added when this setting is enabled.
348       *
349       * <p>
350       * Note the differences between the following settings:
351       * <ul class='javatree'>
352       *    <li class='jf'>{@link #addRootType()} - Affects whether <js>'_type'</js> is added to root node.
353       *    <li class='jf'>{@link #addBeanTypes()} - Affects whether <js>'_type'</js> is added to any nodes.
354       * </ul>
355       *
356       * <h5 class='section'>Example:</h5>
357       * <p class='bjava'>
358       *    <jc>// Create a serializer that adds _type to root node.</jc>
359       *    WriterSerializer <jv>serializer</jv>= JsonSerializer
360       *       .<jsm>create</jsm>()
361       *       .addRootType()
362       *       .build();
363       *
364       *    <jc>// Our bean to serialize.</jc>
365       *    <ja>@Bean</ja>(typeName=<js>"mybean"</js>)
366       *    <jk>public class</jk> MyBean {
367       *       <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>;
368       *    }
369       *
370       *    <jc>// Will contain:  {"_type":"mybean","foo":"bar"}</jc>
371       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
372       * </p>
373       *
374       * @return This object.
375       */
376      public Builder addRootType() {
377         return addRootType(true);
378      }
379
380      /**
381       * Same as {@link #addRootType()} but allows you to explicitly specify the value.
382       *
383       * @param value The value for this setting.
384       * @return This object.
385       */
386      public Builder addRootType(boolean value) {
387         addRootType = value;
388         return this;
389      }
390
391      /**
392       * Don't trim null bean property values.
393       *
394       * <p>
395       * When enabled, null bean values will be serialized to the output.
396       *
397       * <h5 class='section'>Notes:</h5><ul>
398       *    <li class='note'>Not enabling this setting will cause <c>Map</c>s with <jk>null</jk> values to be lost during parsing.
399       * </ul>
400       *
401       * <h5 class='section'>Example:</h5>
402       * <p class='bjava'>
403       *    <jc>// Create a serializer that serializes null properties.</jc>
404       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
405       *       .<jsm>create</jsm>()
406       *       .keepNullProperties()
407       *       .build();
408       *
409       *    <jc>// Our bean to serialize.</jc>
410       *    <jk>public class</jk> MyBean {
411       *       <jk>public</jk> String <jf>foo</jf> = <jk>null</jk>;
412       *    }
413       *
414       *    <jc>// Will contain "{foo:null}".</jc>
415       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
416       * </p>
417       *
418       * @return This object.
419       */
420      public Builder keepNullProperties() {
421         return keepNullProperties(true);
422      }
423
424      /**
425       * Same as {@link #keepNullProperties()} but allows you to explicitly specify the value.
426       *
427       * @param value The value for this setting.
428       * @return This object.
429       */
430      public Builder keepNullProperties(boolean value) {
431         keepNullProperties = value;
432         return this;
433      }
434
435      /**
436       * Serializer listener.
437       *
438       * <p>
439       * Class used to listen for errors and warnings that occur during serialization.
440       *
441       * <h5 class='section'>Example:</h5>
442       * <p class='bjava'>
443       *    <jc>// Define our serializer listener.</jc>
444       *    <jc>// Simply captures all errors.</jc>
445       *    <jk>public class</jk> MySerializerListener <jk>extends</jk> SerializerListener {
446       *
447       *       <jc>// A simple property to store our events.</jc>
448       *       <jk>public</jk> List&lt;String&gt; <jf>events</jf> = <jk>new</jk> LinkedList&lt;&gt;();
449       *
450       *       <ja>@Override</ja>
451       *       <jk>public</jk> &lt;T&gt; <jk>void</jk> onError(SerializerSession <jv>session</jv>, Throwable <jv>throwable</jv>, String <jv>msg</jv>) {
452       *          <jf>events</jf>.add(<jv>session</jv>.getLastLocation() + <js>","</js> + <jv>msg</jv> + <js>","</js> + <jv>throwable</jv>);
453       *       }
454       *    }
455       *
456       *    <jc>// Create a serializer using our listener.</jc>
457       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
458       *       .<jsm>create</jsm>()
459       *       .listener(MySerializerListener.<jk>class</jk>)
460       *       .build();
461       *
462       *    <jc>// Create a session object.</jc>
463       *    <jc>// Needed because listeners are created per-session.</jc>
464       *    <jk>try</jk> (WriterSerializerSession <jv>session</jv> = <jv>serializer</jv>.createSession()) {
465       *
466       *       <jc>// Serialize a bean.</jc>
467       *       String <jv>json</jv> = <jv>session</jv>.serialize(<jk>new</jk> MyBean());
468       *
469       *       <jc>// Get the listener.</jc>
470       *       MySerializerListener <jv>listener</jv> = <jv>session</jv>.getListener(MySerializerListener.<jk>class</jk>);
471       *
472       *       <jc>// Dump the results to the console.</jc>
473       *       Json5.<jsf>DEFAULT</jsf>.println(<jv>listener</jv>.<jf>events</jf>);
474       *    }
475       * </p>
476       *
477       * @param value
478       *    The new value for this property.
479       * @return This object.
480       */
481      public Builder listener(Class<? extends SerializerListener> value) {
482         listener = value;
483         return this;
484      }
485
486      /**
487       * Sort arrays and collections alphabetically.
488       *
489       * <p>
490       * When enabled, copies and sorts the contents of arrays and collections before serializing them.
491       *
492       * <p>
493       * Note that this introduces a performance penalty since it requires copying the existing collection.
494       *
495       * <h5 class='section'>Example:</h5>
496       * <p class='bjava'>
497       *    <jc>// Create a serializer that sorts arrays and collections before serialization.</jc>
498       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
499       *       .<jsm>create</jsm>()
500       *       .sortCollections()
501       *       .build();
502       *
503       *    <jc>// An unsorted array</jc>
504       *    String[] <jv>myArray</jv> = {<js>"foo"</js>,<js>"bar"</js>,<js>"baz"</js>};
505       *
506       *    <jc>// Produces ["bar","baz","foo"]</jc>
507       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jv>myArray</jv>);
508       * </p>
509       *
510       * @return This object.
511       */
512      public Builder sortCollections() {
513         return sortCollections(true);
514      }
515
516      /**
517       * Same as {@link #sortCollections()} but allows you to explicitly specify the value.
518       *
519       * @param value The value for this setting.
520       * @return This object.
521       */
522      public Builder sortCollections(boolean value) {
523         sortCollections = value;
524         return this;
525      }
526
527      /**
528       * Sort maps alphabetically.
529       *
530       * <p>
531       * When enabled, copies and sorts the contents of maps by their keys before serializing them.
532       *
533       * <p>
534       * Note that this introduces a performance penalty.
535       *
536       * <h5 class='section'>Example:</h5>
537       * <p class='bjava'>
538       *    <jc>// Create a serializer that sorts maps before serialization.</jc>
539       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
540       *       .<jsm>create</jsm>()
541       *       .sortMaps()
542       *       .build();
543       *
544       *    <jc>// An unsorted map.</jc>
545       *    JsonMap <jv>myMap</jv> = JsonMap.<jsm>of</jsm>(<js>"foo"</js>,1,<js>"bar"</js>,2,<js>"baz"</js>,3);
546       *
547       *    <jc>// Produces {"bar":2,"baz":3,"foo":1}</jc>
548       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jv>myMap</jv>);
549       * </p>
550       *
551       * @return This object.
552       */
553      public Builder sortMaps() {
554         return sortMaps(true);
555      }
556
557      /**
558       * Same as {@link #sortMaps()} but allows you to explicitly specify the value.
559       *
560       * @param value The value for this setting.
561       * @return This object.
562       */
563      public Builder sortMaps(boolean value) {
564         sortMaps = value;
565         return this;
566      }
567
568      /**
569       * Trim empty lists and arrays.
570       *
571       * <p>
572       * When enabled, empty lists and arrays will not be serialized.
573       *
574       * <p>
575       * Note that enabling this setting has the following effects on parsing:
576       * <ul class='spaced-list'>
577       *    <li>
578       *       Map entries with empty list values will be lost.
579       *    <li>
580       *       Bean properties with empty list values will not be set.
581       * </ul>
582       *
583       * <h5 class='section'>Example:</h5>
584       * <p class='bjava'>
585       *    <jc>// Create a serializer that skips empty arrays and collections.</jc>
586       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
587       *       .<jsm>create</jsm>()
588       *       .trimEmptyCollections()
589       *       .build();
590       *
591       *    <jc>// A bean with a field with an empty array.</jc>
592       *    <jk>public class</jk> MyBean {
593       *       <jk>public</jk> String[] <jf>foo</jf> = {};
594       *    }
595       *
596       *    <jc>// Produces {}</jc>
597       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
598       * </p>
599       *
600       * @return This object.
601       */
602      public Builder trimEmptyCollections() {
603         return trimEmptyCollections(true);
604      }
605
606      /**
607       * Same as {@link #trimEmptyCollections()} but allows you to explicitly specify the value.
608       *
609       * @param value The value for this setting.
610       * @return This object.
611       */
612      public Builder trimEmptyCollections(boolean value) {
613         trimEmptyCollections = value;
614         return this;
615      }
616
617      /**
618       * Trim empty maps.
619       *
620       * <p>
621       * When enabled, empty map values will not be serialized to the output.
622       *
623       * <p>
624       * Note that enabling this setting has the following effects on parsing:
625       * <ul class='spaced-list'>
626       *    <li>
627       *       Bean properties with empty map values will not be set.
628       * </ul>
629       *
630       * <h5 class='section'>Example:</h5>
631       * <p class='bjava'>
632       *    <jc>// Create a serializer that skips empty maps.</jc>
633       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
634       *       .<jsm>create</jsm>()
635       *       .trimEmptyMaps()
636       *       .build();
637       *
638       *    <jc>// A bean with a field with an empty map.</jc>
639       *    <jk>public class</jk> MyBean {
640       *       <jk>public</jk> JsonMap <jf>foo</jf> = JsonMap.<jsm>of</jsm>();
641       *    }
642       *
643       *    <jc>// Produces {}</jc>
644       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(<jk>new</jk> MyBean());
645       * </p>
646       *
647       * @return This object.
648       */
649      public Builder trimEmptyMaps() {
650         return trimEmptyMaps(true);
651      }
652
653      /**
654       * Same as {@link #trimEmptyMaps()} but allows you to explicitly specify the value.
655       *
656       * @param value The value for this setting.
657       * @return This object.
658       */
659      public Builder trimEmptyMaps(boolean value) {
660         trimEmptyMaps = value;
661         return this;
662      }
663
664      /**
665       * Trim strings.
666       *
667       * <p>
668       * When enabled, string values will be trimmed of whitespace using {@link String#trim()} before being serialized.
669       *
670       * <h5 class='section'>Example:</h5>
671       * <p class='bjava'>
672       *    <jc>// Create a serializer that trims strings before serialization.</jc>
673       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
674       *       .<jsm>create</jsm>()
675       *       .trimStrings()
676       *       .build();
677       *
678       * <jc>// A map with space-padded keys/values</jc>
679       *    JsonMap <jv>myMap</jv> = JsonMap.<jsm>of</jsm>(<js>" foo "</js>, <js>" bar "</js>);
680       *
681       *    <jc>// Produces "{foo:'bar'}"</jc>
682       *    String <jv>json</jv> = <jv>serializer</jv>.toString(<jv>myMap</jv>);
683       * </p>
684       *
685       * @return This object.
686       */
687      public Builder trimStrings() {
688         return trimStrings(true);
689      }
690
691      /**
692       * Same as {@link #trimStrings()} but allows you to explicitly specify the value.
693       *
694       * @param value The value for this setting.
695       * @return This object.
696       */
697      public Builder trimStrings(boolean value) {
698         trimStrings = value;
699         return this;
700      }
701
702      /**
703       * URI context bean.
704       *
705       * <p>
706       * Bean used for resolution of URIs to absolute or root-relative form.
707       *
708       * <h5 class='section'>Example:</h5>
709       * <p class='bjava'>
710       *    <jc>// Our URI contextual information.</jc>
711       *    String <jv>authority</jv> = <js>"http://localhost:10000"</js>;
712       *    String <jv>contextRoot</jv> = <js>"/myContext"</js>;
713       *    String <jv>servletPath</jv> = <js>"/myServlet"</js>;
714       *    String <jv>pathInfo</jv> = <js>"/foo"</js>;
715       *
716       *    <jc>// Create a UriContext object.</jc>
717       *    UriContext <jv>uriContext</jv> = <jk>new</jk> UriContext(<jv>authority</jv>, <jv>contextRoot</jv>, <jv>servletPath</jv>, <jv>pathInfo</jv>);
718       *
719       *    <jc>// Associate it with our serializer.</jc>
720       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
721       *       .<jsm>create</jsm>()
722       *       .uriContext(<jv>uriContext</jv>)
723       *       .uriRelativity(<jsf>RESOURCE</jsf>)  <jc>// Assume relative paths are relative to servlet.</jc>
724       *       .uriResolution(<jsf>ABSOLUTE</jsf>)  <jc>// Serialize URLs as absolute paths.</jc>
725       *       .build();
726       *
727       *    <jc>// A relative URL</jc>
728       *    URL <jv>myUrl</jv> = <jk>new</jk> URL(<js>"bar"</js>);
729       *
730       *    <jc>// Produces "http://localhost:10000/myContext/myServlet/foo/bar"</jc>
731       *    String <jv>json</jv> = <jv>serializer</jv>.toString(<jv>myUrl</jv>);
732       * </p>
733       *
734       * <h5 class='section'>See Also:</h5><ul>
735       *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/MarshallingUris">URIs</a>
736       * </ul>
737       *
738       * @param value The new value for this property.
739       * @return This object.
740       */
741      public Builder uriContext(UriContext value) {
742         uriContext = value;
743         return this;
744      }
745
746      /**
747       * URI relativity.
748       *
749       * <p>
750       * Defines what relative URIs are relative to when serializing any of the following:
751       * <ul>
752       *    <li>{@link java.net.URI}
753       *    <li>{@link java.net.URL}
754       *    <li>Properties and classes annotated with {@link Uri @Uri}
755       * </ul>
756       *
757       * <p>
758       * See {@link #uriContext(UriContext)} for examples.
759       *
760       * <ul class='values javatree'>
761       *    <li class='jf'>{@link org.apache.juneau.UriRelativity#RESOURCE}
762       *       - Relative URIs should be considered relative to the servlet URI.
763       *    <li class='jf'>{@link org.apache.juneau.UriRelativity#PATH_INFO}
764       *       - Relative URIs should be considered relative to the request URI.
765       * </ul>
766       *
767       * <h5 class='section'>See Also:</h5><ul>
768       *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/MarshallingUris">URIs</a>
769       * </ul>
770       *
771       * @param value
772       *    The new value for this property.
773       *    <br>The default is {@link UriRelativity#RESOURCE}
774       * @return This object.
775       */
776      public Builder uriRelativity(UriRelativity value) {
777         uriRelativity = value;
778         return this;
779      }
780
781      /**
782       * URI resolution.
783       *
784       * <p>
785       * Defines the resolution level for URIs when serializing any of the following:
786       * <ul>
787       *    <li>{@link java.net.URI}
788       *    <li>{@link java.net.URL}
789       *    <li>Properties and classes annotated with {@link Uri @Uri}
790       * </ul>
791       *
792       * <p>
793       * See {@link #uriContext(UriContext)} for examples.
794       *
795       * <ul class='values javatree'>
796       *    <li class='jf'>{@link UriResolution#ABSOLUTE}
797       *       - Resolve to an absolute URL (e.g. <js>"http://host:port/context-root/servlet-path/path-info"</js>).
798       *    <li class='jf'>{@link UriResolution#ROOT_RELATIVE}
799       *       - Resolve to a root-relative URL (e.g. <js>"/context-root/servlet-path/path-info"</js>).
800       *    <li class='jf'>{@link UriResolution#NONE}
801       *       - Don't do any URL resolution.
802       * </ul>
803       *
804       * <h5 class='section'>See Also:</h5><ul>
805       *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/MarshallingUris">URIs</a>
806       * </ul>
807       *
808       * @param value
809       *    The new value for this property.
810       *    <br>The default is {@link UriResolution#NONE}
811       * @return This object.
812       */
813      public Builder uriResolution(UriResolution value) {
814         uriResolution = value;
815         return this;
816      }
817      @Override /* Overridden from Builder */
818      public Builder annotations(Annotation...values) {
819         super.annotations(values);
820         return this;
821      }
822
823      @Override /* Overridden from Builder */
824      public Builder apply(AnnotationWorkList work) {
825         super.apply(work);
826         return this;
827      }
828
829      @Override /* Overridden from Builder */
830      public Builder applyAnnotations(Object...from) {
831         super.applyAnnotations(from);
832         return this;
833      }
834
835      @Override /* Overridden from Builder */
836      public Builder applyAnnotations(Class<?>...from) {
837         super.applyAnnotations(from);
838         return this;
839      }
840
841      @Override /* Overridden from Builder */
842      public Builder cache(Cache<HashKey,? extends org.apache.juneau.Context> value) {
843         super.cache(value);
844         return this;
845      }
846
847      @Override /* Overridden from Builder */
848      public Builder debug() {
849         super.debug();
850         return this;
851      }
852
853      @Override /* Overridden from Builder */
854      public Builder debug(boolean value) {
855         super.debug(value);
856         return this;
857      }
858
859      @Override /* Overridden from Builder */
860      public Builder impl(Context value) {
861         super.impl(value);
862         return this;
863      }
864
865      @Override /* Overridden from Builder */
866      public Builder type(Class<? extends org.apache.juneau.Context> value) {
867         super.type(value);
868         return this;
869      }
870
871      @Override /* Overridden from Builder */
872      public Builder beanClassVisibility(Visibility value) {
873         super.beanClassVisibility(value);
874         return this;
875      }
876
877      @Override /* Overridden from Builder */
878      public Builder beanConstructorVisibility(Visibility value) {
879         super.beanConstructorVisibility(value);
880         return this;
881      }
882
883      @Override /* Overridden from Builder */
884      public Builder beanContext(BeanContext value) {
885         super.beanContext(value);
886         return this;
887      }
888
889      @Override /* Overridden from Builder */
890      public Builder beanContext(BeanContext.Builder value) {
891         super.beanContext(value);
892         return this;
893      }
894
895      @Override /* Overridden from Builder */
896      public Builder beanDictionary(java.lang.Class<?>...values) {
897         super.beanDictionary(values);
898         return this;
899      }
900
901      @Override /* Overridden from Builder */
902      public Builder beanFieldVisibility(Visibility value) {
903         super.beanFieldVisibility(value);
904         return this;
905      }
906
907      @Override /* Overridden from Builder */
908      public Builder beanInterceptor(Class<?> on, Class<? extends org.apache.juneau.swap.BeanInterceptor<?>> value) {
909         super.beanInterceptor(on, value);
910         return this;
911      }
912
913      @Override /* Overridden from Builder */
914      public Builder beanMapPutReturnsOldValue() {
915         super.beanMapPutReturnsOldValue();
916         return this;
917      }
918
919      @Override /* Overridden from Builder */
920      public Builder beanMethodVisibility(Visibility value) {
921         super.beanMethodVisibility(value);
922         return this;
923      }
924
925      @Override /* Overridden from Builder */
926      public Builder beanProperties(Map<String,Object> values) {
927         super.beanProperties(values);
928         return this;
929      }
930
931      @Override /* Overridden from Builder */
932      public Builder beanProperties(Class<?> beanClass, String properties) {
933         super.beanProperties(beanClass, properties);
934         return this;
935      }
936
937      @Override /* Overridden from Builder */
938      public Builder beanProperties(String beanClassName, String properties) {
939         super.beanProperties(beanClassName, properties);
940         return this;
941      }
942
943      @Override /* Overridden from Builder */
944      public Builder beanPropertiesExcludes(Map<String,Object> values) {
945         super.beanPropertiesExcludes(values);
946         return this;
947      }
948
949      @Override /* Overridden from Builder */
950      public Builder beanPropertiesExcludes(Class<?> beanClass, String properties) {
951         super.beanPropertiesExcludes(beanClass, properties);
952         return this;
953      }
954
955      @Override /* Overridden from Builder */
956      public Builder beanPropertiesExcludes(String beanClassName, String properties) {
957         super.beanPropertiesExcludes(beanClassName, properties);
958         return this;
959      }
960
961      @Override /* Overridden from Builder */
962      public Builder beanPropertiesReadOnly(Map<String,Object> values) {
963         super.beanPropertiesReadOnly(values);
964         return this;
965      }
966
967      @Override /* Overridden from Builder */
968      public Builder beanPropertiesReadOnly(Class<?> beanClass, String properties) {
969         super.beanPropertiesReadOnly(beanClass, properties);
970         return this;
971      }
972
973      @Override /* Overridden from Builder */
974      public Builder beanPropertiesReadOnly(String beanClassName, String properties) {
975         super.beanPropertiesReadOnly(beanClassName, properties);
976         return this;
977      }
978
979      @Override /* Overridden from Builder */
980      public Builder beanPropertiesWriteOnly(Map<String,Object> values) {
981         super.beanPropertiesWriteOnly(values);
982         return this;
983      }
984
985      @Override /* Overridden from Builder */
986      public Builder beanPropertiesWriteOnly(Class<?> beanClass, String properties) {
987         super.beanPropertiesWriteOnly(beanClass, properties);
988         return this;
989      }
990
991      @Override /* Overridden from Builder */
992      public Builder beanPropertiesWriteOnly(String beanClassName, String properties) {
993         super.beanPropertiesWriteOnly(beanClassName, properties);
994         return this;
995      }
996
997      @Override /* Overridden from Builder */
998      public Builder beansRequireDefaultConstructor() {
999         super.beansRequireDefaultConstructor();
1000         return this;
1001      }
1002
1003      @Override /* Overridden from Builder */
1004      public Builder beansRequireSerializable() {
1005         super.beansRequireSerializable();
1006         return this;
1007      }
1008
1009      @Override /* Overridden from Builder */
1010      public Builder beansRequireSettersForGetters() {
1011         super.beansRequireSettersForGetters();
1012         return this;
1013      }
1014
1015      @Override /* Overridden from Builder */
1016      public Builder dictionaryOn(Class<?> on, java.lang.Class<?>...values) {
1017         super.dictionaryOn(on, values);
1018         return this;
1019      }
1020
1021      @Override /* Overridden from Builder */
1022      public Builder disableBeansRequireSomeProperties() {
1023         super.disableBeansRequireSomeProperties();
1024         return this;
1025      }
1026
1027      @Override /* Overridden from Builder */
1028      public Builder disableIgnoreMissingSetters() {
1029         super.disableIgnoreMissingSetters();
1030         return this;
1031      }
1032
1033      @Override /* Overridden from Builder */
1034      public Builder disableIgnoreTransientFields() {
1035         super.disableIgnoreTransientFields();
1036         return this;
1037      }
1038
1039      @Override /* Overridden from Builder */
1040      public Builder disableIgnoreUnknownNullBeanProperties() {
1041         super.disableIgnoreUnknownNullBeanProperties();
1042         return this;
1043      }
1044
1045      @Override /* Overridden from Builder */
1046      public Builder disableInterfaceProxies() {
1047         super.disableInterfaceProxies();
1048         return this;
1049      }
1050
1051      @Override /* Overridden from Builder */
1052      public <T> Builder example(Class<T> pojoClass, T o) {
1053         super.example(pojoClass, o);
1054         return this;
1055      }
1056
1057      @Override /* Overridden from Builder */
1058      public <T> Builder example(Class<T> pojoClass, String json) {
1059         super.example(pojoClass, json);
1060         return this;
1061      }
1062
1063      @Override /* Overridden from Builder */
1064      public Builder findFluentSetters() {
1065         super.findFluentSetters();
1066         return this;
1067      }
1068
1069      @Override /* Overridden from Builder */
1070      public Builder findFluentSetters(Class<?> on) {
1071         super.findFluentSetters(on);
1072         return this;
1073      }
1074
1075      @Override /* Overridden from Builder */
1076      public Builder ignoreInvocationExceptionsOnGetters() {
1077         super.ignoreInvocationExceptionsOnGetters();
1078         return this;
1079      }
1080
1081      @Override /* Overridden from Builder */
1082      public Builder ignoreInvocationExceptionsOnSetters() {
1083         super.ignoreInvocationExceptionsOnSetters();
1084         return this;
1085      }
1086
1087      @Override /* Overridden from Builder */
1088      public Builder ignoreUnknownBeanProperties() {
1089         super.ignoreUnknownBeanProperties();
1090         return this;
1091      }
1092
1093      @Override /* Overridden from Builder */
1094      public Builder ignoreUnknownEnumValues() {
1095         super.ignoreUnknownEnumValues();
1096         return this;
1097      }
1098
1099      @Override /* Overridden from Builder */
1100      public Builder implClass(Class<?> interfaceClass, Class<?> implClass) {
1101         super.implClass(interfaceClass, implClass);
1102         return this;
1103      }
1104
1105      @Override /* Overridden from Builder */
1106      public Builder implClasses(Map<Class<?>,Class<?>> values) {
1107         super.implClasses(values);
1108         return this;
1109      }
1110
1111      @Override /* Overridden from Builder */
1112      public Builder interfaceClass(Class<?> on, Class<?> value) {
1113         super.interfaceClass(on, value);
1114         return this;
1115      }
1116
1117      @Override /* Overridden from Builder */
1118      public Builder interfaces(java.lang.Class<?>...value) {
1119         super.interfaces(value);
1120         return this;
1121      }
1122
1123      @Override /* Overridden from Builder */
1124      public Builder locale(Locale value) {
1125         super.locale(value);
1126         return this;
1127      }
1128
1129      @Override /* Overridden from Builder */
1130      public Builder mediaType(MediaType value) {
1131         super.mediaType(value);
1132         return this;
1133      }
1134
1135      @Override /* Overridden from Builder */
1136      public Builder notBeanClasses(java.lang.Class<?>...values) {
1137         super.notBeanClasses(values);
1138         return this;
1139      }
1140
1141      @Override /* Overridden from Builder */
1142      public Builder notBeanPackages(String...values) {
1143         super.notBeanPackages(values);
1144         return this;
1145      }
1146
1147      @Override /* Overridden from Builder */
1148      public Builder propertyNamer(Class<? extends org.apache.juneau.PropertyNamer> value) {
1149         super.propertyNamer(value);
1150         return this;
1151      }
1152
1153      @Override /* Overridden from Builder */
1154      public Builder propertyNamer(Class<?> on, Class<? extends org.apache.juneau.PropertyNamer> value) {
1155         super.propertyNamer(on, value);
1156         return this;
1157      }
1158
1159      @Override /* Overridden from Builder */
1160      public Builder sortProperties() {
1161         super.sortProperties();
1162         return this;
1163      }
1164
1165      @Override /* Overridden from Builder */
1166      public Builder sortProperties(java.lang.Class<?>...on) {
1167         super.sortProperties(on);
1168         return this;
1169      }
1170
1171      @Override /* Overridden from Builder */
1172      public Builder stopClass(Class<?> on, Class<?> value) {
1173         super.stopClass(on, value);
1174         return this;
1175      }
1176
1177      @Override /* Overridden from Builder */
1178      public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction) {
1179         super.swap(normalClass, swappedClass, swapFunction);
1180         return this;
1181      }
1182
1183      @Override /* Overridden from Builder */
1184      public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction, ThrowingFunction<S,T> unswapFunction) {
1185         super.swap(normalClass, swappedClass, swapFunction, unswapFunction);
1186         return this;
1187      }
1188
1189      @Override /* Overridden from Builder */
1190      public Builder swaps(Object...values) {
1191         super.swaps(values);
1192         return this;
1193      }
1194
1195      @Override /* Overridden from Builder */
1196      public Builder swaps(Class<?>...values) {
1197         super.swaps(values);
1198         return this;
1199      }
1200
1201      @Override /* Overridden from Builder */
1202      public Builder timeZone(TimeZone value) {
1203         super.timeZone(value);
1204         return this;
1205      }
1206
1207      @Override /* Overridden from Builder */
1208      public Builder typeName(Class<?> on, String value) {
1209         super.typeName(on, value);
1210         return this;
1211      }
1212
1213      @Override /* Overridden from Builder */
1214      public Builder typePropertyName(String value) {
1215         super.typePropertyName(value);
1216         return this;
1217      }
1218
1219      @Override /* Overridden from Builder */
1220      public Builder typePropertyName(Class<?> on, String value) {
1221         super.typePropertyName(on, value);
1222         return this;
1223      }
1224
1225      @Override /* Overridden from Builder */
1226      public Builder useEnumNames() {
1227         super.useEnumNames();
1228         return this;
1229      }
1230
1231      @Override /* Overridden from Builder */
1232      public Builder useJavaBeanIntrospector() {
1233         super.useJavaBeanIntrospector();
1234         return this;
1235      }
1236
1237      @Override /* Overridden from Builder */
1238      public Builder detectRecursions() {
1239         super.detectRecursions();
1240         return this;
1241      }
1242
1243      @Override /* Overridden from Builder */
1244      public Builder detectRecursions(boolean value) {
1245         super.detectRecursions(value);
1246         return this;
1247      }
1248
1249      @Override /* Overridden from Builder */
1250      public Builder ignoreRecursions() {
1251         super.ignoreRecursions();
1252         return this;
1253      }
1254
1255      @Override /* Overridden from Builder */
1256      public Builder ignoreRecursions(boolean value) {
1257         super.ignoreRecursions(value);
1258         return this;
1259      }
1260
1261      @Override /* Overridden from Builder */
1262      public Builder initialDepth(int value) {
1263         super.initialDepth(value);
1264         return this;
1265      }
1266
1267      @Override /* Overridden from Builder */
1268      public Builder maxDepth(int value) {
1269         super.maxDepth(value);
1270         return this;
1271      }
1272   }
1273
1274   //-------------------------------------------------------------------------------------------------------------------
1275   // Instance
1276   //-------------------------------------------------------------------------------------------------------------------
1277
1278   final String produces, accept;
1279   final boolean
1280      addBeanTypes,
1281      keepNullProperties,
1282      trimEmptyCollections,
1283      trimEmptyMaps,
1284      trimStrings,
1285      sortCollections,
1286      sortMaps,
1287      addRootType;
1288   final UriContext uriContext;
1289   final UriResolution uriResolution;
1290   final UriRelativity uriRelativity;
1291   final Class<? extends SerializerListener> listener;
1292
1293   private final MediaRanges acceptRanges;
1294   private final MediaType[] acceptMediaTypes;
1295   private final MediaType producesMediaType;
1296
1297   /**
1298    * Constructor
1299    *
1300    * @param builder The builder this object.
1301    */
1302   protected Serializer(Builder builder) {
1303      super(builder);
1304
1305      produces = builder.produces;
1306      accept = builder.accept;
1307      addBeanTypes = builder.addBeanTypes;
1308      keepNullProperties = builder.keepNullProperties;
1309      trimEmptyCollections = builder.trimEmptyCollections;
1310      trimEmptyMaps = builder.trimEmptyMaps;
1311      trimStrings = builder.trimStrings;
1312      sortCollections = builder.sortCollections;
1313      sortMaps = builder.sortMaps;
1314      addRootType = builder.addRootType;
1315      uriContext = builder.uriContext;
1316      uriResolution = builder.uriResolution;
1317      uriRelativity = builder.uriRelativity;
1318      listener = builder.listener;
1319
1320      this.producesMediaType = MediaType.of(produces);
1321      this.acceptRanges = accept != null ? MediaRanges.of(accept) : MediaRanges.of(produces);
1322      this.acceptMediaTypes = builder.accept != null ? MediaType.ofAll(splita(builder.accept)) : new MediaType[] {this.producesMediaType};
1323   }
1324
1325   @Override /* Context */
1326   public Builder copy() {
1327      return new Builder(this);
1328   }
1329
1330   @Override /* Context */
1331   public SerializerSession.Builder createSession() {
1332      return SerializerSession.create(this);
1333   }
1334
1335   @Override /* Context */
1336   public SerializerSession getSession() {
1337      return createSession().build();
1338   }
1339
1340   /**
1341    * Returns <jk>true</jk> if this serializer subclasses from {@link WriterSerializer}.
1342    *
1343    * @return <jk>true</jk> if this serializer subclasses from {@link WriterSerializer}.
1344    */
1345   public boolean isWriterSerializer() {
1346      return false;
1347   }
1348
1349   //-----------------------------------------------------------------------------------------------------------------
1350   // Convenience methods
1351   //-----------------------------------------------------------------------------------------------------------------
1352
1353   /**
1354    * Serializes a POJO to the specified output stream or writer.
1355    *
1356    * <p>
1357    * Equivalent to calling <c>serializer.createSession().serialize(o, output);</c>
1358    *
1359    * @param o The object to serialize.
1360    * @param output
1361    *    The output object.
1362    *    <br>Character-based serializers can handle the following output class types:
1363    *    <ul>
1364    *       <li>{@link Writer}
1365    *       <li>{@link OutputStream} - Output will be written as UTF-8 encoded stream.
1366    *       <li>{@link File} - Output will be written as system-default encoded stream.
1367    *       <li>{@link StringBuilder} - Output will be written to the specified string builder.
1368    *    </ul>
1369    *    <br>Stream-based serializers can handle the following output class types:
1370    *    <ul>
1371    *       <li>{@link OutputStream}
1372    *       <li>{@link File}
1373    *    </ul>
1374    * @throws SerializeException If a problem occurred trying to convert the output.
1375    * @throws IOException Thrown by the underlying stream.
1376    */
1377   public final void serialize(Object o, Object output) throws SerializeException, IOException {
1378      getSession().serialize(o, output);
1379   }
1380
1381   /**
1382    * Shortcut method for serializing objects directly to either a <c>String</c> or <code><jk>byte</jk>[]</code>
1383    * depending on the serializer type.
1384    *
1385    * @param o The object to serialize.
1386    * @return
1387    *    The serialized object.
1388    *    <br>Character-based serializers will return a <c>String</c>
1389    *    <br>Stream-based serializers will return a <code><jk>byte</jk>[]</code>
1390    * @throws SerializeException If a problem occurred trying to convert the output.
1391    */
1392   public Object serialize(Object o) throws SerializeException {
1393      return getSession().serialize(o);
1394   }
1395
1396   /**
1397    * Convenience method for serializing an object to a String.
1398    *
1399    * <p>
1400    * For writer-based serializers, this is identical to calling {@link #serialize(Object)}.
1401    * <br>For stream-based serializers, this converts the returned byte array to a string based on
1402    * the {@link OutputStreamSerializer.Builder#binaryFormat(BinaryFormat)} setting.
1403    *
1404    * @param o The object to serialize.
1405    * @return The output serialized to a string.
1406    * @throws SerializeException If a problem occurred trying to convert the output.
1407    */
1408   public final String serializeToString(Object o) throws SerializeException {
1409      return getSession().serializeToString(o);
1410   }
1411
1412   //-----------------------------------------------------------------------------------------------------------------
1413   // Other methods
1414   //-----------------------------------------------------------------------------------------------------------------
1415
1416   /**
1417    * Serializes a POJO to the specified pipe.
1418    *
1419    * @param session The current session.
1420    * @param pipe Where to send the output from the serializer.
1421    * @param o The object to serialize.
1422    * @throws IOException Thrown by underlying stream.
1423    * @throws SerializeException Problem occurred trying to serialize object.
1424    */
1425   protected void doSerialize(SerializerSession session, SerializerPipe pipe, Object o) throws IOException, SerializeException {
1426      throw new UnsupportedOperationException();
1427   }
1428
1429   /**
1430    * Optional method that specifies HTTP request headers for this serializer.
1431    *
1432    * <p>
1433    * For example, {@link SoapXmlSerializer} needs to set a <c>SOAPAction</c> header.
1434    *
1435    * <p>
1436    * This method is typically meaningless if the serializer is being used stand-alone (i.e. outside of a REST server
1437    * or client).
1438    *
1439    * @param session The current session.
1440    * @return
1441    *    The HTTP headers to set on HTTP requests.
1442    *    Never <jk>null</jk>.
1443    */
1444   public Map<String,String> getResponseHeaders(SerializerSession session) {
1445      return Collections.emptyMap();
1446   }
1447
1448   /**
1449    * Returns the media types handled based on the value of the <c>accept</c> parameter passed into the constructor.
1450    *
1451    * <p>
1452    * Note that the order of these ranges are from high to low q-value.
1453    *
1454    * @return The list of media types.  Never <jk>null</jk>.
1455    */
1456   public final MediaRanges getMediaTypeRanges() {
1457      return acceptRanges;
1458   }
1459
1460   /**
1461    * Returns the first entry in the <c>accept</c> parameter passed into the constructor.
1462    *
1463    * <p>
1464    * This signifies the 'primary' media type for this serializer.
1465    *
1466    * @return The media type.  Never <jk>null</jk>.
1467    */
1468   public final MediaType getPrimaryMediaType() {
1469      return acceptMediaTypes[0];
1470   }
1471
1472   /**
1473    * Performs an action on the media types handled based on the value of the <c>accept</c> parameter passed into the constructor.
1474    *
1475    * <p>
1476    * The order of the media types are the same as those in the <c>accept</c> parameter.
1477    *
1478    * @param action The action to perform on the media types.
1479    * @return This object.
1480    */
1481   public final Serializer forEachAcceptMediaType(Consumer<MediaType> action) {
1482      for (MediaType m : acceptMediaTypes)
1483         action.accept(m);
1484      return this;
1485   }
1486
1487   /**
1488    * Optional method that returns the response <c>Content-Type</c> for this serializer if it is different from
1489    * the matched media type.
1490    *
1491    * <p>
1492    * This method is specified to override the content type for this serializer.
1493    * For example, the {@link org.apache.juneau.json.Json5Serializer} class returns that it handles media type
1494    * <js>"text/json5"</js>, but returns <js>"text/json"</js> as the actual content type.
1495    * This allows clients to request specific 'flavors' of content using specialized <c>Accept</c> header values.
1496    *
1497    * <p>
1498    * This method is typically meaningless if the serializer is being used stand-alone (i.e. outside of a REST server
1499    * or client).
1500    *
1501    * @return The response content type.  If <jk>null</jk>, then the matched media type is used.
1502    */
1503   public final MediaType getResponseContentType() {
1504      return producesMediaType;
1505   }
1506
1507   //-----------------------------------------------------------------------------------------------------------------
1508   // Properties
1509   //-----------------------------------------------------------------------------------------------------------------
1510
1511   /**
1512    * Add <js>"_type"</js> properties when needed.
1513    *
1514    * @see Serializer.Builder#addBeanTypes()
1515    * @return
1516    *    <jk>true</jk> if <js>"_type"</js> properties added to beans if their type cannot be inferred
1517    *    through reflection.
1518    */
1519   protected boolean isAddBeanTypes() {
1520      return addBeanTypes;
1521   }
1522
1523   /**
1524    * Add type attribute to root nodes.
1525    *
1526    * @see Serializer.Builder#addRootType()
1527    * @return
1528    *    <jk>true</jk> if type property should be added to root node.
1529    */
1530   protected final boolean isAddRootType() {
1531      return addRootType;
1532   }
1533
1534   /**
1535    * Serializer listener.
1536    *
1537    * @see Serializer.Builder#listener(Class)
1538    * @return
1539    *    Class used to listen for errors and warnings that occur during serialization.
1540    */
1541   protected final Class<? extends SerializerListener> getListener() {
1542      return listener;
1543   }
1544
1545   /**
1546    * Sort arrays and collections alphabetically.
1547    *
1548    * @see Serializer.Builder#sortCollections()
1549    * @return
1550    *    <jk>true</jk> if arrays and collections are copied and sorted before serialization.
1551    */
1552   protected final boolean isSortCollections() {
1553      return sortCollections;
1554   }
1555
1556   /**
1557    * Sort maps alphabetically.
1558    *
1559    * @see Serializer.Builder#sortMaps()
1560    * @return
1561    *    <jk>true</jk> if maps are copied and sorted before serialization.
1562    */
1563   protected final boolean isSortMaps() {
1564      return sortMaps;
1565   }
1566
1567   /**
1568    * Trim empty lists and arrays.
1569    *
1570    * @see Serializer.Builder#trimEmptyCollections()
1571    * @return
1572    *    <jk>true</jk> if empty lists and arrays are not serialized to the output.
1573    */
1574   protected final boolean isTrimEmptyCollections() {
1575      return trimEmptyCollections;
1576   }
1577
1578   /**
1579    * Trim empty maps.
1580    *
1581    * @see Serializer.Builder#trimEmptyMaps()
1582    * @return
1583    *    <jk>true</jk> if empty map values are not serialized to the output.
1584    */
1585   protected final boolean isTrimEmptyMaps() {
1586      return trimEmptyMaps;
1587   }
1588
1589   /**
1590    * Don't trim null bean property values.
1591    *
1592    * @see Serializer.Builder#keepNullProperties()
1593    * @return
1594    *    <jk>true</jk> if null bean values are serialized to the output.
1595    */
1596   protected final boolean isKeepNullProperties() {
1597      return keepNullProperties;
1598   }
1599
1600   /**
1601    * Trim strings.
1602    *
1603    * @see Serializer.Builder#trimStrings()
1604    * @return
1605    *    <jk>true</jk> if string values will be trimmed of whitespace using {@link String#trim()} before being serialized.
1606    */
1607   protected final boolean isTrimStrings() {
1608      return trimStrings;
1609   }
1610
1611   /**
1612    * URI context bean.
1613    *
1614    * @see Serializer.Builder#uriContext(UriContext)
1615    * @return
1616    *    Bean used for resolution of URIs to absolute or root-relative form.
1617    */
1618   protected final UriContext getUriContext() {
1619      return uriContext;
1620   }
1621
1622   /**
1623    * URI relativity.
1624    *
1625    * @see Serializer.Builder#uriRelativity(UriRelativity)
1626    * @return
1627    *    Defines what relative URIs are relative to when serializing any of the following:
1628    */
1629   protected final UriRelativity getUriRelativity() {
1630      return uriRelativity;
1631   }
1632
1633   /**
1634    * URI resolution.
1635    *
1636    * @see Serializer.Builder#uriResolution(UriResolution)
1637    * @return
1638    *    Defines the resolution level for URIs when serializing URIs.
1639    */
1640   protected final UriResolution getUriResolution() {
1641      return uriResolution;
1642   }
1643
1644   //-----------------------------------------------------------------------------------------------------------------
1645   // Other methods
1646   //-----------------------------------------------------------------------------------------------------------------
1647
1648   @Override /* Context */
1649   protected JsonMap properties() {
1650      return filteredMap()
1651         .append("addBeanTypes", addBeanTypes)
1652         .append("keepNullProperties", keepNullProperties)
1653         .append("trimEmptyCollections", trimEmptyCollections)
1654         .append("trimEmptyMaps", trimEmptyMaps)
1655         .append("trimStrings", trimStrings)
1656         .append("sortCollections", sortCollections)
1657         .append("sortMaps", sortMaps)
1658         .append("addRootType", addRootType)
1659         .append("uriContext", uriContext)
1660         .append("uriResolution", uriResolution)
1661         .append("uriRelativity", uriRelativity)
1662         .append("listener", listener);
1663   }
1664}