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