View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.juneau.serializer;
18  
19  import static org.apache.juneau.commons.utils.AssertionUtils.*;
20  import static org.apache.juneau.commons.utils.CollectionUtils.*;
21  import static org.apache.juneau.commons.utils.StringUtils.*;
22  import static org.apache.juneau.commons.utils.ThrowableUtils.*;
23  import static org.apache.juneau.commons.utils.Utils.*;
24  
25  import java.io.*;
26  import java.lang.annotation.*;
27  import java.util.*;
28  import java.util.function.*;
29  
30  import org.apache.juneau.*;
31  import org.apache.juneau.annotation.*;
32  import org.apache.juneau.commons.collections.*;
33  import org.apache.juneau.commons.function.*;
34  import org.apache.juneau.commons.reflect.*;
35  import org.apache.juneau.soap.*;
36  
37  /**
38   * Parent class for all Juneau serializers.
39   *
40   * <h5 class='topic'>Description</h5>
41   * <p>
42   * Base serializer class that serves as the parent class for all serializers.
43   *
44   * <p>
45   * The purpose of this class is:
46   * <ul>
47   * 	<li>Maintain a read-only configuration state of a serializer.
48   * 	<li>Create session objects used for serializing POJOs (i.e. {@link SerializerSession}).
49   * 	<li>Provide convenience methods for serializing POJOs without having to construct session objects.
50   * </ul>
51   *
52   * <p>
53   * Subclasses should (but are not required to) extend directly from {@link OutputStreamSerializer} or {@link WriterSerializer} depending on
54   * whether it's a stream or character based serializer.
55   *
56   * <p>
57   * Subclasses must implement parsing via one of the following methods:
58   * <ul class='javatree'>
59   * 	<li class='jmp'>{@link #doSerialize(SerializerSession, SerializerPipe, Object)}
60   * 	<li class='jmp'>{@link SerializerSession#doSerialize(SerializerPipe, Object)}
61   * </ul>
62   * <br>
63   *
64   * <h5 class='section'>Notes:</h5><ul>
65   * 	<li class='note'>This class is thread safe and reusable.
66   * </ul>
67   *
68   * <h5 class='section'>See Also:</h5><ul>
69   * 	<li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/SerializersAndParsers">Serializers and Parsers</a>
70  
71   * </ul>
72   */
73  public class Serializer extends BeanTraverseContext {
74  	/**
75  	 * Builder class.
76  	 */
77  	public static class Builder extends BeanTraverseContext.Builder {
78  
79  		private boolean addBeanTypes;
80  		private boolean addRootType;
81  		private boolean keepNullProperties;
82  		private boolean sortCollections;
83  		private boolean sortMaps;
84  		private boolean trimEmptyCollections;
85  		private boolean trimEmptyMaps;
86  		private boolean trimStrings;
87  		private Class<? extends SerializerListener> listener;
88  		private String accept;
89  		private String produces;
90  		private UriContext uriContext;
91  		private UriRelativity uriRelativity;
92  		private UriResolution uriResolution;
93  
94  		/**
95  		 * Constructor, default settings.
96  		 */
97  		protected Builder() {
98  			produces = null;
99  			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 }