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