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