1 package com.fasterxml.jackson.databind;
2
3 import java.io.*;
4 import java.text.*;
5 import java.util.Locale;
6 import java.util.Map;
7 import java.util.TimeZone;
8 import java.util.concurrent.atomic.AtomicReference;
9
10 import com.fasterxml.jackson.core.*;
11 import com.fasterxml.jackson.core.io.CharacterEscapes;
12 import com.fasterxml.jackson.core.io.SegmentedStringWriter;
13 import com.fasterxml.jackson.core.io.SerializedString;
14 import com.fasterxml.jackson.core.type.TypeReference;
15 import com.fasterxml.jackson.core.util.*;
16 import com.fasterxml.jackson.databind.cfg.ContextAttributes;
17 import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
18 import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
19 import com.fasterxml.jackson.databind.ser.*;
20 import com.fasterxml.jackson.databind.ser.impl.TypeWrappedSerializer;
21 import com.fasterxml.jackson.databind.type.TypeFactory;
22 import com.fasterxml.jackson.databind.util.ClassUtil;
23
24 /**
25 * Builder object that can be used for per-serialization configuration of
26 * serialization parameters, such as JSON View and root type to use.
27 * (and thus fully thread-safe with no external synchronization);
28 * new instances are constructed for different configurations.
29 * Instances are initially constructed by {@link ObjectMapper} and can be
30 * reused in completely thread-safe manner with no explicit synchronization
31 */
32 public class ObjectWriter
33 implements Versioned,
34 java.io.Serializable // since 2.1
35 {
36 private static final long serialVersionUID = 1; // since 2.5
37
38 /**
39 * We need to keep track of explicit disabling of pretty printing;
40 * easiest to do by a token value.
41 */
42 protected final static PrettyPrinter NULL_PRETTY_PRINTER = new MinimalPrettyPrinter();
43
44 /*
45 /**********************************************************
46 /* Immutable configuration from ObjectMapper
47 /**********************************************************
48 */
49
50 /**
51 * General serialization configuration settings
52 */
53 protected final SerializationConfig _config;
54
55 protected final DefaultSerializerProvider _serializerProvider;
56
57 protected final SerializerFactory _serializerFactory;
58
59 /**
60 * Factory used for constructing {@link JsonGenerator}s
61 */
62 protected final JsonFactory _generatorFactory;
63
64 /*
65 /**********************************************************
66 /* Configuration that can be changed via mutant factories
67 /**********************************************************
68 */
69
70 /**
71 * Container for settings that need to be passed to {@link JsonGenerator}
72 * constructed for serializing values.
73 *
74 * @since 2.5
75 */
76 protected final GeneratorSettings _generatorSettings;
77
78 /**
79 * We may pre-fetch serializer if root type
80 * is known (has been explicitly declared), and if so, reuse it afterwards.
81 * This allows avoiding further serializer lookups and increases
82 * performance a bit on cases where readers are reused.
83 *
84 * @since 2.5
85 */
86 protected final Prefetch _prefetch;
87
88 /*
89 /**********************************************************
90 /* Life-cycle, constructors
91 /**********************************************************
92 */
93
94 /**
95 * Constructor used by {@link ObjectMapper} for initial instantiation
96 */
97 protected ObjectWriter(ObjectMapper mapper, SerializationConfig config,
98 JavaType rootType, PrettyPrinter pp)
99 {
100 _config = config;
101 _serializerProvider = mapper._serializerProvider;
102 _serializerFactory = mapper._serializerFactory;
103 _generatorFactory = mapper._jsonFactory;
104 _generatorSettings = (pp == null) ? GeneratorSettings.empty
105 : new GeneratorSettings(pp, null, null, null);
106
107 if (rootType == null) {
108 _prefetch = Prefetch.empty;
109 } else if (rootType.hasRawClass(Object.class)) {
110 // 15-Sep-2019, tatu: There is no "untyped serializer", but...
111 // as per [databind#1093] we do need `TypeSerializer`
112 _prefetch = Prefetch.empty.forRootType(this, rootType);
113 } else {
114 _prefetch = Prefetch.empty.forRootType(this, rootType.withStaticTyping());
115 }
116 }
117
118 /**
119 * Alternative constructor for initial instantiation by {@link ObjectMapper}
120 */
121 protected ObjectWriter(ObjectMapper mapper, SerializationConfig config)
122 {
123 _config = config;
124 _serializerProvider = mapper._serializerProvider;
125 _serializerFactory = mapper._serializerFactory;
126 _generatorFactory = mapper._jsonFactory;
127
128 _generatorSettings = GeneratorSettings.empty;
129 _prefetch = Prefetch.empty;
130 }
131
132 /**
133 * Alternative constructor for initial instantiation by {@link ObjectMapper}
134 */
135 protected ObjectWriter(ObjectMapper mapper, SerializationConfig config,
136 FormatSchema s)
137 {
138 _config = config;
139
140 _serializerProvider = mapper._serializerProvider;
141 _serializerFactory = mapper._serializerFactory;
142 _generatorFactory = mapper._jsonFactory;
143
144 _generatorSettings = (s == null) ? GeneratorSettings.empty
145 : new GeneratorSettings(null, s, null, null);
146 _prefetch = Prefetch.empty;
147 }
148
149 /**
150 * Copy constructor used for building variations.
151 */
152 protected ObjectWriter(ObjectWriter base, SerializationConfig config,
153 GeneratorSettings genSettings, Prefetch prefetch)
154 {
155 _config = config;
156
157 _serializerProvider = base._serializerProvider;
158 _serializerFactory = base._serializerFactory;
159 _generatorFactory = base._generatorFactory;
160
161 _generatorSettings = genSettings;
162 _prefetch = prefetch;
163 }
164
165 /**
166 * Copy constructor used for building variations.
167 */
168 protected ObjectWriter(ObjectWriter base, SerializationConfig config)
169 {
170 _config = config;
171
172 _serializerProvider = base._serializerProvider;
173 _serializerFactory = base._serializerFactory;
174 _generatorFactory = base._generatorFactory;
175
176 _generatorSettings = base._generatorSettings;
177 _prefetch = base._prefetch;
178 }
179
180 /**
181 * @since 2.3
182 */
183 protected ObjectWriter(ObjectWriter base, JsonFactory f)
184 {
185 // may need to override ordering, based on data format capabilities
186 _config = base._config
187 .with(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, f.requiresPropertyOrdering());
188
189 _serializerProvider = base._serializerProvider;
190 _serializerFactory = base._serializerFactory;
191 _generatorFactory = f;
192
193 _generatorSettings = base._generatorSettings;
194 _prefetch = base._prefetch;
195 }
196
197 /**
198 * Method that will return version information stored in and read from jar
199 * that contains this class.
200 */
201 @Override
202 public Version version() {
203 return com.fasterxml.jackson.databind.cfg.PackageVersion.VERSION;
204 }
205
206 /*
207 /**********************************************************************
208 /* Internal factory methods, for convenience
209 /**********************************************************************
210 */
211
212 /**
213 * Overridable factory method called by various "withXxx()" methods
214 *
215 * @since 2.5
216 */
217 protected ObjectWriter _new(ObjectWriter base, JsonFactory f) {
218 return new ObjectWriter(base, f);
219 }
220
221 /**
222 * Overridable factory method called by various "withXxx()" methods
223 *
224 * @since 2.5
225 */
226 protected ObjectWriter _new(ObjectWriter base, SerializationConfig config) {
227 if (config == _config) {
228 return this;
229 }
230 return new ObjectWriter(base, config);
231 }
232
233 /**
234 * Overridable factory method called by various "withXxx()" methods.
235 * It assumes `this` as base for settings other than those directly
236 * passed in.
237 *
238 * @since 2.5
239 */
240 protected ObjectWriter _new(GeneratorSettings genSettings, Prefetch prefetch) {
241 if ((_generatorSettings == genSettings) && (_prefetch == prefetch)) {
242 return this;
243 }
244 return new ObjectWriter(this, _config, genSettings, prefetch);
245 }
246
247 /**
248 * Overridable factory method called by {@link #writeValues(OutputStream)}
249 * method (and its various overrides), and initializes it as necessary.
250 *
251 * @since 2.5
252 */
253 @SuppressWarnings("resource")
254 protected SequenceWriter _newSequenceWriter(boolean wrapInArray,
255 JsonGenerator gen, boolean managedInput)
256 throws IOException
257 {
258 return new SequenceWriter(_serializerProvider(),
259 _configureGenerator(gen), managedInput, _prefetch)
260 .init(wrapInArray);
261 }
262
263 /*
264 /**********************************************************
265 /* Life-cycle, fluent factories for SerializationFeature
266 /**********************************************************
267 */
268
269 /**
270 * Method for constructing a new instance that is configured
271 * with specified feature enabled.
272 */
273 public ObjectWriter with(SerializationFeature feature) {
274 return _new(this, _config.with(feature));
275 }
276
277 /**
278 * Method for constructing a new instance that is configured
279 * with specified features enabled.
280 */
281 public ObjectWriter with(SerializationFeature first, SerializationFeature... other) {
282 return _new(this, _config.with(first, other));
283 }
284
285 /**
286 * Method for constructing a new instance that is configured
287 * with specified features enabled.
288 */
289 public ObjectWriter withFeatures(SerializationFeature... features) {
290 return _new(this, _config.withFeatures(features));
291 }
292
293 /**
294 * Method for constructing a new instance that is configured
295 * with specified feature enabled.
296 */
297 public ObjectWriter without(SerializationFeature feature) {
298 return _new(this, _config.without(feature));
299 }
300
301 /**
302 * Method for constructing a new instance that is configured
303 * with specified features enabled.
304 */
305 public ObjectWriter without(SerializationFeature first, SerializationFeature... other) {
306 return _new(this, _config.without(first, other));
307 }
308
309 /**
310 * Method for constructing a new instance that is configured
311 * with specified features enabled.
312 */
313 public ObjectWriter withoutFeatures(SerializationFeature... features) {
314 return _new(this, _config.withoutFeatures(features));
315 }
316
317 /*
318 /**********************************************************
319 /* Life-cycle, fluent factories for JsonGenerator.Feature (2.5)
320 /**********************************************************
321 */
322
323 /**
324 * @since 2.5
325 */
326 public ObjectWriter with(JsonGenerator.Feature feature) {
327 return _new(this, _config.with(feature));
328 }
329
330 /**
331 * @since 2.5
332 */
333 public ObjectWriter withFeatures(JsonGenerator.Feature... features) {
334 return _new(this, _config.withFeatures(features));
335 }
336
337 /**
338 * @since 2.5
339 */
340 public ObjectWriter without(JsonGenerator.Feature feature) {
341 return _new(this, _config.without(feature));
342 }
343
344 /**
345 * @since 2.5
346 */
347 public ObjectWriter withoutFeatures(JsonGenerator.Feature... features) {
348 return _new(this, _config.withoutFeatures(features));
349 }
350
351 /*
352 /**********************************************************
353 /* Life-cycle, fluent factories for StreamWriteFeature (2.11)
354 /**********************************************************
355 */
356
357 /**
358 * @since 2.11
359 */
360 public ObjectWriter with(StreamWriteFeature feature) {
361 return _new(this, _config.with(feature.mappedFeature()));
362 }
363
364 /**
365 * @since 2.11
366 */
367 public ObjectWriter without(StreamWriteFeature feature) {
368 return _new(this, _config.without(feature.mappedFeature()));
369 }
370
371 /*
372 /**********************************************************
373 /* Life-cycle, fluent factories for FormatFeature (2.7)
374 /**********************************************************
375 */
376
377 /**
378 * @since 2.7
379 */
380 public ObjectWriter with(FormatFeature feature) {
381 return _new(this, _config.with(feature));
382 }
383
384 /**
385 * @since 2.7
386 */
387 public ObjectWriter withFeatures(FormatFeature... features) {
388 return _new(this, _config.withFeatures(features));
389 }
390
391 /**
392 * @since 2.7
393 */
394 public ObjectWriter without(FormatFeature feature) {
395 return _new(this, _config.without(feature));
396 }
397
398 /**
399 * @since 2.7
400 */
401 public ObjectWriter withoutFeatures(FormatFeature... features) {
402 return _new(this, _config.withoutFeatures(features));
403 }
404
405 /*
406 /**********************************************************
407 /* Life-cycle, fluent factories, type-related
408 /**********************************************************
409 */
410
411 /**
412 * Method that will construct a new instance that uses specific type
413 * as the root type for serialization, instead of runtime dynamic
414 * type of the root object itself.
415 *<p>
416 * Note that method does NOT change state of this reader, but
417 * rather construct and returns a newly configured instance.
418 *
419 * @since 2.5
420 */
421 public ObjectWriter forType(JavaType rootType) {
422 return _new(_generatorSettings, _prefetch.forRootType(this, rootType));
423 }
424
425 /**
426 * Method that will construct a new instance that uses specific type
427 * as the root type for serialization, instead of runtime dynamic
428 * type of the root object itself.
429 *
430 * @since 2.5
431 */
432 public ObjectWriter forType(Class<?> rootType) {
433 return forType(_config.constructType(rootType));
434 }
435
436 /**
437 * Method that will construct a new instance that uses specific type
438 * as the root type for serialization, instead of runtime dynamic
439 * type of the root object itself.
440 *
441 * @since 2.5
442 */
443 public ObjectWriter forType(TypeReference<?> rootType) {
444 return forType(_config.getTypeFactory().constructType(rootType.getType()));
445 }
446
447 /**
448 * @deprecated since 2.5 Use {@link #forType(JavaType)} instead
449 */
450 @Deprecated // since 2.5
451 public ObjectWriter withType(JavaType rootType) {
452 return forType(rootType);
453 }
454
455 /**
456 * @deprecated since 2.5 Use {@link #forType(Class)} instead
457 */
458 @Deprecated // since 2.5
459 public ObjectWriter withType(Class<?> rootType) {
460 return forType(rootType);
461 }
462
463 /**
464 * @deprecated since 2.5 Use {@link #forType(TypeReference)} instead
465 */
466 @Deprecated // since 2.5
467 public ObjectWriter withType(TypeReference<?> rootType) {
468 return forType(rootType);
469 }
470
471 /*
472 /**********************************************************
473 /* Life-cycle, fluent factories, other
474 /**********************************************************
475 */
476
477 /**
478 * Fluent factory method that will construct a new writer instance that will
479 * use specified date format for serializing dates; or if null passed, one
480 * that will serialize dates as numeric timestamps.
481 *<p>
482 * Note that the method does NOT change state of this reader, but
483 * rather construct and returns a newly configured instance.
484 */
485 public ObjectWriter with(DateFormat df) {
486 return _new(this, _config.with(df));
487 }
488
489 /**
490 * Method that will construct a new instance that will use the default
491 * pretty printer for serialization.
492 */
493 public ObjectWriter withDefaultPrettyPrinter() {
494 return with(_config.getDefaultPrettyPrinter());
495 }
496
497 /**
498 * Method that will construct a new instance that uses specified
499 * provider for resolving filter instances by id.
500 */
501 public ObjectWriter with(FilterProvider filterProvider) {
502 if (filterProvider == _config.getFilterProvider()) {
503 return this;
504 }
505 return _new(this, _config.withFilters(filterProvider));
506 }
507
508 /**
509 * Method that will construct a new instance that will use specified pretty
510 * printer (or, if null, will not do any pretty-printing)
511 */
512 public ObjectWriter with(PrettyPrinter pp) {
513 return _new(_generatorSettings.with(pp), _prefetch);
514 }
515
516 /**
517 * Method for constructing a new instance with configuration that
518 * specifies what root name to use for "root element wrapping".
519 * See {@link SerializationConfig#withRootName(String)} for details.
520 *<p>
521 * Note that method does NOT change state of this reader, but
522 * rather construct and returns a newly configured instance.
523 *
524 * @param rootName Root name to use, if non-empty; `null` for "use defaults",
525 * and empty String ("") for "do NOT add root wrapper"
526 */
527 public ObjectWriter withRootName(String rootName) {
528 return _new(this, _config.withRootName(rootName));
529 }
530
531 /**
532 * @since 2.6
533 */
534 public ObjectWriter withRootName(PropertyName rootName) {
535 return _new(this, _config.withRootName(rootName));
536 }
537
538 /**
539 * Convenience method that is same as calling:
540 *<code>
541 * withRootName("")
542 *</code>
543 * which will forcibly prevent use of root name wrapping when writing
544 * values with this {@link ObjectWriter}.
545 *
546 * @since 2.6
547 */
548 public ObjectWriter withoutRootName() {
549 return _new(this, _config.withRootName(PropertyName.NO_NAME));
550 }
551
552 /**
553 * Method that will construct a new instance that uses specific format schema
554 * for serialization.
555 *<p>
556 * Note that method does NOT change state of this reader, but
557 * rather construct and returns a newly configured instance.
558 */
559 public ObjectWriter with(FormatSchema schema) {
560 _verifySchemaType(schema);
561 return _new(_generatorSettings.with(schema), _prefetch);
562 }
563
564 /**
565 * @deprecated Since 2.5 use {@link #with(FormatSchema)} instead
566 */
567 @Deprecated
568 public ObjectWriter withSchema(FormatSchema schema) {
569 return with(schema);
570 }
571
572 /**
573 * Method that will construct a new instance that uses specified
574 * serialization view for serialization (with null basically disables
575 * view processing)
576 *<p>
577 * Note that the method does NOT change state of this reader, but
578 * rather construct and returns a newly configured instance.
579 */
580 public ObjectWriter withView(Class<?> view) {
581 return _new(this, _config.withView(view));
582 }
583
584 public ObjectWriter with(Locale l) {
585 return _new(this, _config.with(l));
586 }
587
588 public ObjectWriter with(TimeZone tz) {
589 return _new(this, _config.with(tz));
590 }
591
592 /**
593 * Method that will construct a new instance that uses specified default
594 * {@link Base64Variant} for base64 encoding
595 *
596 * @since 2.1
597 */
598 public ObjectWriter with(Base64Variant b64variant) {
599 return _new(this, _config.with(b64variant));
600 }
601
602 /**
603 * @since 2.3
604 */
605 public ObjectWriter with(CharacterEscapes escapes) {
606 return _new(_generatorSettings.with(escapes), _prefetch);
607 }
608
609 /**
610 * @since 2.3
611 */
612 public ObjectWriter with(JsonFactory f) {
613 return (f == _generatorFactory) ? this : _new(this, f);
614 }
615
616 /**
617 * @since 2.3
618 */
619 public ObjectWriter with(ContextAttributes attrs) {
620 return _new(this, _config.with(attrs));
621 }
622
623 /**
624 * Mutant factory method that allows construction of a new writer instance
625 * that uses specified set of default attribute values.
626 *
627 * @since 2.3
628 */
629 public ObjectWriter withAttributes(Map<?,?> attrs) {
630 return _new(this, _config.withAttributes(attrs));
631 }
632
633 /**
634 * @since 2.3
635 */
636 public ObjectWriter withAttribute(Object key, Object value) {
637 return _new(this, _config.withAttribute(key, value));
638 }
639
640 /**
641 * @since 2.3
642 */
643 public ObjectWriter withoutAttribute(Object key) {
644 return _new(this, _config.withoutAttribute(key));
645 }
646
647 /**
648 * @since 2.5
649 */
650 public ObjectWriter withRootValueSeparator(String sep) {
651 return _new(_generatorSettings.withRootValueSeparator(sep), _prefetch);
652 }
653
654 /**
655 * @since 2.5
656 */
657 public ObjectWriter withRootValueSeparator(SerializableString sep) {
658 return _new(_generatorSettings.withRootValueSeparator(sep), _prefetch);
659 }
660
661 /*
662 /**********************************************************
663 /* Factory methods for creating JsonGenerators (added in 2.11)
664 /**********************************************************
665 */
666
667 /**
668 * Factory method for constructing properly initialized {@link JsonGenerator}
669 * to write content using specified {@link OutputStream}.
670 * Generator is not managed (or "owned") by ObjectWriter: caller is responsible
671 * for properly closing it once content generation is complete.
672 *
673 * @since 2.11
674 */
675 public JsonGenerator createGenerator(OutputStream out) throws IOException {
676 _assertNotNull("out", out);
677 return _configureGenerator(_generatorFactory.createGenerator(out, JsonEncoding.UTF8));
678 }
679
680 /**
681 * Factory method for constructing properly initialized {@link JsonGenerator}
682 * to write content using specified {@link OutputStream} and encoding.
683 * Generator is not managed (or "owned") by ObjectWriter: caller is responsible
684 * for properly closing it once content generation is complete.
685 *
686 * @since 2.11
687 */
688 public JsonGenerator createGenerator(OutputStream out, JsonEncoding enc) throws IOException {
689 _assertNotNull("out", out);
690 return _configureGenerator(_generatorFactory.createGenerator(out, enc));
691 }
692
693 /**
694 * Factory method for constructing properly initialized {@link JsonGenerator}
695 * to write content using specified {@link Writer}.
696 * Generator is not managed (or "owned") by ObjectWriter: caller is responsible
697 * for properly closing it once content generation is complete.
698 *
699 * @since 2.11
700 */
701 public JsonGenerator createGenerator(Writer w) throws IOException {
702 _assertNotNull("w", w);
703 return _configureGenerator(_generatorFactory.createGenerator(w));
704 }
705
706 /**
707 * Factory method for constructing properly initialized {@link JsonGenerator}
708 * to write content to specified {@link File}, using specified encoding.
709 * Generator is not managed (or "owned") by ObjectWriter: caller is responsible
710 * for properly closing it once content generation is complete.
711 *
712 * @since 2.11
713 */
714 public JsonGenerator createGenerator(File outputFile, JsonEncoding enc) throws IOException {
715 _assertNotNull("outputFile", outputFile);
716 return _configureGenerator(_generatorFactory.createGenerator(outputFile, enc));
717 }
718
719 /**
720 * Factory method for constructing properly initialized {@link JsonGenerator}
721 * to write content using specified {@link DataOutput}.
722 * Generator is not managed (or "owned") by ObjectWriter: caller is responsible
723 * for properly closing it once content generation is complete.
724 *
725 * @since 2.11
726 */
727 public JsonGenerator createGenerator(DataOutput out) throws IOException {
728 _assertNotNull("out", out);
729 return _configureGenerator(_generatorFactory.createGenerator(out));
730 }
731
732 /*
733 /**********************************************************
734 /* Factory methods for sequence writers (2.5)
735 /**********************************************************
736 */
737
738 /**
739 * Method for creating a {@link SequenceWriter} to write a sequence of root
740 * values using configuration of this {@link ObjectWriter}.
741 * Sequence is not surrounded by JSON array; some backend types may not
742 * support writing of such sequences as root level.
743 * Resulting writer needs to be {@link SequenceWriter#close()}d after all
744 * values have been written to ensure closing of underlying generator and
745 * output stream.
746 *
747 * @param out Target file to write value sequence to.
748 *
749 * @since 2.5
750 */
751 public SequenceWriter writeValues(File out) throws IOException {
752 return _newSequenceWriter(false, createGenerator(out, JsonEncoding.UTF8), true);
753 }
754
755 /**
756 * Method for creating a {@link SequenceWriter} to write a sequence of root
757 * values using configuration of this {@link ObjectWriter}.
758 * Sequence is not surrounded by JSON array; some backend types may not
759 * support writing of such sequences as root level.
760 * Resulting writer needs to be {@link SequenceWriter#close()}d after all
761 * values have been written to ensure that all content gets flushed by
762 * the generator. However, since a {@link JsonGenerator} is explicitly passed,
763 * it will NOT be closed when {@link SequenceWriter#close()} is called.
764 *
765 * @param g Low-level generator caller has already constructed that will
766 * be used for actual writing of token stream.
767 *
768 * @since 2.5
769 */
770 public SequenceWriter writeValues(JsonGenerator g) throws IOException {
771 _assertNotNull("g", g);
772 return _newSequenceWriter(false, _configureGenerator(g), false);
773 }
774
775 /**
776 * Method for creating a {@link SequenceWriter} to write a sequence of root
777 * values using configuration of this {@link ObjectWriter}.
778 * Sequence is not surrounded by JSON array; some backend types may not
779 * support writing of such sequences as root level.
780 * Resulting writer needs to be {@link SequenceWriter#close()}d after all
781 * values have been written to ensure closing of underlying generator and
782 * output stream.
783 *
784 * @param out Target writer to use for writing the token stream
785 *
786 * @since 2.5
787 */
788 public SequenceWriter writeValues(Writer out) throws IOException {
789 return _newSequenceWriter(false, createGenerator(out), true);
790 }
791
792 /**
793 * Method for creating a {@link SequenceWriter} to write a sequence of root
794 * values using configuration of this {@link ObjectWriter}.
795 * Sequence is not surrounded by JSON array; some backend types may not
796 * support writing of such sequences as root level.
797 * Resulting writer needs to be {@link SequenceWriter#close()}d after all
798 * values have been written to ensure closing of underlying generator and
799 * output stream.
800 *
801 * @param out Physical output stream to use for writing the token stream
802 *
803 * @since 2.5
804 */
805 public SequenceWriter writeValues(OutputStream out) throws IOException {
806 return _newSequenceWriter(false, createGenerator(out, JsonEncoding.UTF8), true);
807 }
808
809 /**
810 * @since 2.8
811 */
812 public SequenceWriter writeValues(DataOutput out) throws IOException {
813 return _newSequenceWriter(false, createGenerator(out), true);
814 }
815
816 /**
817 * Method for creating a {@link SequenceWriter} to write an array of
818 * root-level values, using configuration of this {@link ObjectWriter}.
819 * Resulting writer needs to be {@link SequenceWriter#close()}d after all
820 * values have been written to ensure closing of underlying generator and
821 * output stream.
822 *<p>
823 * Note that the type to use with {@link ObjectWriter#forType(Class)} needs to
824 * be type of individual values (elements) to write and NOT matching array
825 * or {@link java.util.Collection} type.
826 *
827 * @param out File to write token stream to
828 *
829 * @since 2.5
830 */
831 public SequenceWriter writeValuesAsArray(File out) throws IOException {
832 return _newSequenceWriter(true, createGenerator(out, JsonEncoding.UTF8), true);
833 }
834
835 /**
836 * Method for creating a {@link SequenceWriter} to write an array of
837 * root-level values, using configuration of this {@link ObjectWriter}.
838 * Resulting writer needs to be {@link SequenceWriter#close()}d after all
839 * values have been written to ensure that all content gets flushed by
840 * the generator. However, since a {@link JsonGenerator} is explicitly passed,
841 * it will NOT be closed when {@link SequenceWriter#close()} is called.
842 *<p>
843 * Note that the type to use with {@link ObjectWriter#forType(Class)} needs to
844 * be type of individual values (elements) to write and NOT matching array
845 * or {@link java.util.Collection} type.
846 *
847 * @param gen Underlying generator to use for writing the token stream
848 *
849 * @since 2.5
850 */
851 public SequenceWriter writeValuesAsArray(JsonGenerator gen) throws IOException {
852 _assertNotNull("gen", gen);
853 return _newSequenceWriter(true, gen, false);
854 }
855
856 /**
857 * Method for creating a {@link SequenceWriter} to write an array of
858 * root-level values, using configuration of this {@link ObjectWriter}.
859 * Resulting writer needs to be {@link SequenceWriter#close()}d after all
860 * values have been written to ensure closing of underlying generator and
861 * output stream.
862 *<p>
863 * Note that the type to use with {@link ObjectWriter#forType(Class)} needs to
864 * be type of individual values (elements) to write and NOT matching array
865 * or {@link java.util.Collection} type.
866 *
867 * @param out Writer to use for writing the token stream
868 *
869 * @since 2.5
870 */
871 public SequenceWriter writeValuesAsArray(Writer out) throws IOException {
872 return _newSequenceWriter(true, createGenerator(out), true);
873 }
874
875 /**
876 * Method for creating a {@link SequenceWriter} to write an array of
877 * root-level values, using configuration of this {@link ObjectWriter}.
878 * Resulting writer needs to be {@link SequenceWriter#close()}d after all
879 * values have been written to ensure closing of underlying generator and
880 * output stream.
881 *<p>
882 * Note that the type to use with {@link ObjectWriter#forType(Class)} needs to
883 * be type of individual values (elements) to write and NOT matching array
884 * or {@link java.util.Collection} type.
885 *
886 * @param out Physical output stream to use for writing the token stream
887 *
888 * @since 2.5
889 */
890 public SequenceWriter writeValuesAsArray(OutputStream out) throws IOException {
891 return _newSequenceWriter(true, createGenerator(out, JsonEncoding.UTF8), true);
892 }
893
894 /**
895 * @since 2.8
896 */
897 public SequenceWriter writeValuesAsArray(DataOutput out) throws IOException {
898 return _newSequenceWriter(true, createGenerator(out), true);
899 }
900
901 /*
902 /**********************************************************
903 /* Simple accessors
904 /**********************************************************
905 */
906
907 public boolean isEnabled(SerializationFeature f) {
908 return _config.isEnabled(f);
909 }
910
911 public boolean isEnabled(MapperFeature f) {
912 return _config.isEnabled(f);
913 }
914
915 /**
916 * @since 2.9
917 */
918 @Deprecated
919 public boolean isEnabled(JsonParser.Feature f) {
920 return _generatorFactory.isEnabled(f);
921 }
922
923 /**
924 * @since 2.9
925 */
926 public boolean isEnabled(JsonGenerator.Feature f) {
927 return _generatorFactory.isEnabled(f);
928 }
929
930 /**
931 * @since 2.11
932 */
933 public boolean isEnabled(StreamWriteFeature f) {
934 return _generatorFactory.isEnabled(f);
935 }
936
937 /**
938 * @since 2.2
939 */
940 public SerializationConfig getConfig() {
941 return _config;
942 }
943
944 /**
945 * @since 2.2
946 */
947 public JsonFactory getFactory() {
948 return _generatorFactory;
949 }
950
951 public TypeFactory getTypeFactory() {
952 return _config.getTypeFactory();
953 }
954
955 /**
956 * Diagnostics method that can be called to check whether this writer
957 * has pre-fetched serializer to use: pre-fetching improves performance
958 * when writer instances are reused as it avoids a per-call serializer
959 * lookup.
960 *
961 * @since 2.2
962 */
963 public boolean hasPrefetchedSerializer() {
964 return _prefetch.hasSerializer();
965 }
966
967 /**
968 * @since 2.3
969 */
970 public ContextAttributes getAttributes() {
971 return _config.getAttributes();
972 }
973
974 /*
975 /**********************************************************
976 /* Serialization methods; ones from ObjectCodec first
977 /**********************************************************
978 */
979
980 /**
981 * Method that can be used to serialize any Java value as
982 * JSON output, using provided {@link JsonGenerator}.
983 *<p>
984 * Note that the given {@link JsonGenerator} is not closed; caller
985 * is expected to handle that as necessary.
986 */
987 public void writeValue(JsonGenerator g, Object value) throws IOException
988 {
989 _assertNotNull("g", g);
990 _configureGenerator(g);
991 if (_config.isEnabled(SerializationFeature.CLOSE_CLOSEABLE)
992 && (value instanceof Closeable)) {
993
994 Closeable toClose = (Closeable) value;
995 try {
996 _prefetch.serialize(g, value, _serializerProvider());
997 if (_config.isEnabled(SerializationFeature.FLUSH_AFTER_WRITE_VALUE)) {
998 g.flush();
999 }
1000 } catch (Exception e) {
1001 ClassUtil.closeOnFailAndThrowAsIOE(null, toClose, e);
1002 return;
1003 }
1004 toClose.close();
1005 } else {
1006 _prefetch.serialize(g, value, _serializerProvider());
1007 if (_config.isEnabled(SerializationFeature.FLUSH_AFTER_WRITE_VALUE)) {
1008 g.flush();
1009 }
1010 }
1011 }
1012
1013 /*
1014 /**********************************************************
1015 /* Serialization methods, others
1016 /**********************************************************
1017 */
1018
1019 /**
1020 * Method that can be used to serialize any Java value as
1021 * JSON output, written to File provided.
1022 */
1023 public void writeValue(File resultFile, Object value)
1024 throws IOException, JsonGenerationException, JsonMappingException
1025 {
1026 _writeValueAndClose(createGenerator(resultFile, JsonEncoding.UTF8), value);
1027 }
1028
1029 /**
1030 * Method that can be used to serialize any Java value as
1031 * JSON output, using output stream provided (using encoding
1032 * {@link JsonEncoding#UTF8}).
1033 *<p>
1034 * Note: method does not close the underlying stream explicitly
1035 * here; however, {@link JsonFactory} this mapper uses may choose
1036 * to close the stream depending on its settings (by default,
1037 * it will try to close it when {@link JsonGenerator} we construct
1038 * is closed).
1039 */
1040 public void writeValue(OutputStream out, Object value)
1041 throws IOException, JsonGenerationException, JsonMappingException
1042 {
1043 _writeValueAndClose(createGenerator(out, JsonEncoding.UTF8), value);
1044 }
1045
1046 /**
1047 * Method that can be used to serialize any Java value as
1048 * JSON output, using Writer provided.
1049 *<p>
1050 * Note: method does not close the underlying stream explicitly
1051 * here; however, {@link JsonFactory} this mapper uses may choose
1052 * to close the stream depending on its settings (by default,
1053 * it will try to close it when {@link JsonGenerator} we construct
1054 * is closed).
1055 */
1056 public void writeValue(Writer w, Object value)
1057 throws IOException, JsonGenerationException, JsonMappingException
1058 {
1059 _writeValueAndClose(createGenerator(w), value);
1060 }
1061
1062 /**
1063 * @since 2.8
1064 */
1065 public void writeValue(DataOutput out, Object value)
1066 throws IOException
1067 {
1068 _writeValueAndClose(createGenerator(out), value);
1069 }
1070
1071 /**
1072 * Method that can be used to serialize any Java value as
1073 * a String. Functionally equivalent to calling
1074 * {@link #writeValue(Writer,Object)} with {@link java.io.StringWriter}
1075 * and constructing String, but more efficient.
1076 *<p>
1077 * Note: prior to version 2.1, throws clause included {@link IOException}; 2.1 removed it.
1078 */
1079 @SuppressWarnings("resource")
1080 public String writeValueAsString(Object value)
1081 throws JsonProcessingException
1082 {
1083 // alas, we have to pull the recycler directly here...
1084 SegmentedStringWriter sw = new SegmentedStringWriter(_generatorFactory._getBufferRecycler());
1085 try {
1086 _writeValueAndClose(createGenerator(sw), value);
1087 } catch (JsonProcessingException e) {
1088 throw e;
1089 } catch (IOException e) { // shouldn't really happen, but is declared as possibility so:
1090 throw JsonMappingException.fromUnexpectedIOE(e);
1091 }
1092 return sw.getAndClear();
1093 }
1094
1095 /**
1096 * Method that can be used to serialize any Java value as
1097 * a byte array. Functionally equivalent to calling
1098 * {@link #writeValue(Writer,Object)} with {@link java.io.ByteArrayOutputStream}
1099 * and getting bytes, but more efficient.
1100 * Encoding used will be UTF-8.
1101 *<p>
1102 * Note: prior to version 2.1, throws clause included {@link IOException}; 2.1 removed it.
1103 */
1104 @SuppressWarnings("resource")
1105 public byte[] writeValueAsBytes(Object value)
1106 throws JsonProcessingException
1107 {
1108 ByteArrayBuilder bb = new ByteArrayBuilder(_generatorFactory._getBufferRecycler());
1109 try {
1110 _writeValueAndClose(createGenerator(bb, JsonEncoding.UTF8), value);
1111 } catch (JsonProcessingException e) { // to support [JACKSON-758]
1112 throw e;
1113 } catch (IOException e) { // shouldn't really happen, but is declared as possibility so:
1114 throw JsonMappingException.fromUnexpectedIOE(e);
1115 }
1116 byte[] result = bb.toByteArray();
1117 bb.release();
1118 return result;
1119 }
1120
1121 /*
1122 /**********************************************************
1123 /* Other public methods
1124 /**********************************************************
1125 */
1126
1127 /**
1128 * Method for visiting type hierarchy for given type, using specified visitor.
1129 * Visitation uses <code>Serializer</code> hierarchy and related properties
1130 *<p>
1131 * This method can be used for things like
1132 * generating <a href="http://json-schema.org/">Json Schema</a>
1133 * instance for specified type.
1134 *
1135 * @param type Type to generate schema for (possibly with generic signature)
1136 *
1137 * @since 2.2
1138 */
1139 public void acceptJsonFormatVisitor(JavaType type, JsonFormatVisitorWrapper visitor) throws JsonMappingException
1140 {
1141 _assertNotNull("type", type);
1142 _assertNotNull("visitor", visitor);
1143 _serializerProvider().acceptJsonFormatVisitor(type, visitor);
1144 }
1145
1146 /**
1147 * Since 2.6
1148 */
1149 public void acceptJsonFormatVisitor(Class<?> type, JsonFormatVisitorWrapper visitor) throws JsonMappingException {
1150 _assertNotNull("type", type);
1151 _assertNotNull("visitor", visitor);
1152 acceptJsonFormatVisitor(_config.constructType(type), visitor);
1153 }
1154
1155 public boolean canSerialize(Class<?> type) {
1156 _assertNotNull("type", type);
1157 return _serializerProvider().hasSerializerFor(type, null);
1158 }
1159
1160 /**
1161 * Method for checking whether instances of given type can be serialized,
1162 * and optionally why (as per {@link Throwable} returned).
1163 *
1164 * @since 2.3
1165 */
1166 public boolean canSerialize(Class<?> type, AtomicReference<Throwable> cause) {
1167 _assertNotNull("type", type);
1168 return _serializerProvider().hasSerializerFor(type, cause);
1169 }
1170
1171 /*
1172 /**********************************************************
1173 /* Overridable helper methods
1174 /**********************************************************
1175 */
1176
1177 /**
1178 * Overridable helper method used for constructing
1179 * {@link SerializerProvider} to use for serialization.
1180 */
1181 protected DefaultSerializerProvider _serializerProvider() {
1182 return _serializerProvider.createInstance(_config, _serializerFactory);
1183 }
1184
1185 /*
1186 /**********************************************************
1187 /* Internal methods
1188 /**********************************************************
1189 */
1190
1191 /**
1192 * @since 2.2
1193 */
1194 protected void _verifySchemaType(FormatSchema schema)
1195 {
1196 if (schema != null) {
1197 if (!_generatorFactory.canUseSchema(schema)) {
1198 throw new IllegalArgumentException("Cannot use FormatSchema of type "+schema.getClass().getName()
1199 +" for format "+_generatorFactory.getFormatName());
1200 }
1201 }
1202 }
1203
1204 /**
1205 * Method called to configure the generator as necessary and then
1206 * call write functionality
1207 *
1208 * @since 2.11.2
1209 */
1210 protected final void _writeValueAndClose(JsonGenerator gen, Object value) throws IOException
1211 {
1212 if (_config.isEnabled(SerializationFeature.CLOSE_CLOSEABLE) && (value instanceof Closeable)) {
1213 _writeCloseable(gen, value);
1214 return;
1215 }
1216 try {
1217 _prefetch.serialize(gen, value, _serializerProvider());
1218 } catch (Exception e) {
1219 ClassUtil.closeOnFailAndThrowAsIOE(gen, e);
1220 return;
1221 }
1222 gen.close();
1223 }
1224
1225 /**
1226 * Helper method used when value to serialize is {@link Closeable} and its <code>close()</code>
1227 * method is to be called right after serialization has been called
1228 */
1229 private final void _writeCloseable(JsonGenerator gen, Object value)
1230 throws IOException
1231 {
1232 Closeable toClose = (Closeable) value;
1233 try {
1234 _prefetch.serialize(gen, value, _serializerProvider());
1235 Closeable tmpToClose = toClose;
1236 toClose = null;
1237 tmpToClose.close();
1238 } catch (Exception e) {
1239 ClassUtil.closeOnFailAndThrowAsIOE(gen, toClose, e);
1240 return;
1241 }
1242 gen.close();
1243 }
1244
1245 /**
1246 * Helper method called to set or override settings of passed-in
1247 * {@link JsonGenerator}
1248 *
1249 * @since 2.5
1250 */
1251 protected final JsonGenerator _configureGenerator(JsonGenerator gen)
1252 {
1253 // order is slightly significant: both may change PrettyPrinter
1254 // settings.
1255 _config.initialize(gen); // since 2.5
1256 _generatorSettings.initialize(gen);
1257 return gen;
1258 }
1259
1260 protected final void _assertNotNull(String paramName, Object src) {
1261 if (src == null) {
1262 throw new IllegalArgumentException(String.format("argument \"%s\" is null", paramName));
1263 }
1264 }
1265
1266 /*
1267 /**********************************************************
1268 /* Helper classes for configuration
1269 /**********************************************************
1270 */
1271
1272 /**
1273 * Helper class used for containing settings specifically related
1274 * to (re)configuring {@link JsonGenerator} constructed for
1275 * writing output.
1276 *
1277 * @since 2.5
1278 */
1279 public final static class GeneratorSettings
1280 implements java.io.Serializable
1281 {
1282 private static final long serialVersionUID = 1L;
1283
1284 public final static GeneratorSettings empty = new GeneratorSettings(null, null, null, null);
1285
1286 /**
1287 * To allow for dynamic enabling/disabling of pretty printing,
1288 * pretty printer can be optionally configured for writer
1289 * as well
1290 */
1291 public final PrettyPrinter prettyPrinter;
1292
1293 /**
1294 * When using data format that uses a schema, schema is passed
1295 * to generator.
1296 */
1297 public final FormatSchema schema;
1298
1299 /**
1300 * Caller may want to specify character escaping details, either as
1301 * defaults, or on call-by-call basis.
1302 */
1303 public final CharacterEscapes characterEscapes;
1304
1305 /**
1306 * Caller may want to override so-called "root value separator",
1307 * String added (verbatim, with no quoting or escaping) between
1308 * values in root context. Default value is a single space character,
1309 * but this is often changed to linefeed.
1310 */
1311 public final SerializableString rootValueSeparator;
1312
1313 public GeneratorSettings(PrettyPrinter pp, FormatSchema sch,
1314 CharacterEscapes esc, SerializableString rootSep) {
1315 prettyPrinter = pp;
1316 schema = sch;
1317 characterEscapes = esc;
1318 rootValueSeparator = rootSep;
1319 }
1320
1321 public GeneratorSettings with(PrettyPrinter pp) {
1322 // since null would mean "don't care", need to use placeholder to indicate "disable"
1323 if (pp == null) {
1324 pp = NULL_PRETTY_PRINTER;
1325 }
1326 return (pp == prettyPrinter) ? this
1327 : new GeneratorSettings(pp, schema, characterEscapes, rootValueSeparator);
1328 }
1329
1330 public GeneratorSettings with(FormatSchema sch) {
1331 return (schema == sch) ? this
1332 : new GeneratorSettings(prettyPrinter, sch, characterEscapes, rootValueSeparator);
1333 }
1334
1335 public GeneratorSettings with(CharacterEscapes esc) {
1336 return (characterEscapes == esc) ? this
1337 : new GeneratorSettings(prettyPrinter, schema, esc, rootValueSeparator);
1338 }
1339
1340 public GeneratorSettings withRootValueSeparator(String sep) {
1341 if (sep == null) {
1342 if (rootValueSeparator == null) {
1343 return this;
1344 }
1345 return new GeneratorSettings(prettyPrinter, schema, characterEscapes, null);
1346 }
1347 if (sep.equals(_rootValueSeparatorAsString())) {
1348 return this;
1349 }
1350 return new GeneratorSettings(prettyPrinter, schema, characterEscapes,
1351 new SerializedString(sep));
1352 }
1353
1354 public GeneratorSettings withRootValueSeparator(SerializableString sep) {
1355 if (sep == null) {
1356 if (rootValueSeparator == null) {
1357 return this;
1358 }
1359 return new GeneratorSettings(prettyPrinter, schema, characterEscapes, null);
1360 }
1361 if (sep.equals(rootValueSeparator)) {
1362 return this;
1363 }
1364 return new GeneratorSettings(prettyPrinter, schema, characterEscapes, sep);
1365 }
1366
1367 private final String _rootValueSeparatorAsString() {
1368 return (rootValueSeparator == null) ? null : rootValueSeparator.getValue();
1369 }
1370
1371 /**
1372 * @since 2.6
1373 */
1374 public void initialize(JsonGenerator gen)
1375 {
1376 PrettyPrinter pp = prettyPrinter;
1377 if (prettyPrinter != null) {
1378 if (pp == NULL_PRETTY_PRINTER) {
1379 gen.setPrettyPrinter(null);
1380 } else {
1381 if (pp instanceof Instantiatable<?>) {
1382 pp = (PrettyPrinter) ((Instantiatable<?>) pp).createInstance();
1383 }
1384 gen.setPrettyPrinter(pp);
1385 }
1386 }
1387 if (characterEscapes != null) {
1388 gen.setCharacterEscapes(characterEscapes);
1389 }
1390 if (schema != null) {
1391 gen.setSchema(schema);
1392 }
1393 if (rootValueSeparator != null) {
1394 gen.setRootValueSeparator(rootValueSeparator);
1395 }
1396 }
1397 }
1398
1399 /**
1400 * As a minor optimization, we will make an effort to pre-fetch a serializer,
1401 * or at least relevant <code>TypeSerializer</code>, if given enough
1402 * information.
1403 *
1404 * @since 2.5
1405 */
1406 public final static class Prefetch
1407 implements java.io.Serializable
1408 {
1409 private static final long serialVersionUID = 1L;
1410
1411 public final static Prefetch empty = new Prefetch(null, null, null);
1412
1413 /**
1414 * Specified root serialization type to use; can be same
1415 * as runtime type, but usually one of its super types
1416 * (parent class or interface it implements).
1417 */
1418 private final JavaType rootType;
1419
1420 /**
1421 * We may pre-fetch serializer if {@link #rootType}
1422 * is known, and if so, reuse it afterwards.
1423 * This allows avoiding further serializer lookups and increases
1424 * performance a bit on cases where readers are reused.
1425 */
1426 private final JsonSerializer<Object> valueSerializer;
1427
1428 /**
1429 * When dealing with polymorphic types, we cannot pre-fetch
1430 * serializer, but can pre-fetch {@link TypeSerializer}.
1431 */
1432 private final TypeSerializer typeSerializer;
1433
1434 private Prefetch(JavaType rootT,
1435 JsonSerializer<Object> ser, TypeSerializer typeSer)
1436 {
1437 rootType = rootT;
1438 valueSerializer = ser;
1439 typeSerializer = typeSer;
1440 }
1441
1442 public Prefetch forRootType(ObjectWriter parent, JavaType newType) {
1443 // First: if nominal type not defined not thing much to do
1444 if (newType == null) {
1445 if ((rootType == null) || (valueSerializer == null)) {
1446 return this;
1447 }
1448 return new Prefetch(null, null, null);
1449 }
1450
1451 // Second: if no change, nothing to do either
1452 if (newType.equals(rootType)) {
1453 return this;
1454 }
1455
1456 // But one more trick: `java.lang.Object` has no serialized, but may
1457 // have `TypeSerializer` to use
1458 if (newType.isJavaLangObject()) {
1459 DefaultSerializerProvider prov = parent._serializerProvider();
1460 TypeSerializer typeSer;
1461
1462 try {
1463 typeSer = prov.findTypeSerializer(newType);
1464 } catch (JsonMappingException e) {
1465 // Unlike with value serializer pre-fetch, let's not allow exception
1466 // for TypeSerializer be swallowed
1467 throw new RuntimeJsonMappingException(e);
1468 }
1469 return new Prefetch(null, null, typeSer);
1470 }
1471
1472 if (parent.isEnabled(SerializationFeature.EAGER_SERIALIZER_FETCH)) {
1473 DefaultSerializerProvider prov = parent._serializerProvider();
1474 // 17-Dec-2014, tatu: Need to be bit careful here; TypeSerializers are NOT cached,
1475 // so although it'd seem like a good idea to look for those first, and avoid
1476 // serializer for polymorphic types, it is actually more efficient to do the
1477 // reverse here.
1478 try {
1479 JsonSerializer<Object> ser = prov.findTypedValueSerializer(newType, true, null);
1480 // Important: for polymorphic types, "unwrap"...
1481 if (ser instanceof TypeWrappedSerializer) {
1482 return new Prefetch(newType, null,
1483 ((TypeWrappedSerializer) ser).typeSerializer());
1484 }
1485 return new Prefetch(newType, ser, null);
1486 } catch (JsonMappingException e) {
1487 // need to swallow?
1488 ;
1489 }
1490 }
1491 return new Prefetch(newType, null, typeSerializer);
1492 }
1493
1494 public final JsonSerializer<Object> getValueSerializer() {
1495 return valueSerializer;
1496 }
1497
1498 public final TypeSerializer getTypeSerializer() {
1499 return typeSerializer;
1500 }
1501
1502 public boolean hasSerializer() {
1503 return (valueSerializer != null) || (typeSerializer != null);
1504 }
1505
1506 public void serialize(JsonGenerator gen, Object value, DefaultSerializerProvider prov)
1507 throws IOException
1508 {
1509 if (typeSerializer != null) {
1510 prov.serializePolymorphic(gen, value, rootType, valueSerializer, typeSerializer);
1511 } else if (valueSerializer != null) {
1512 prov.serializeValue(gen, value, rootType, valueSerializer);
1513 } else if (rootType != null) {
1514 prov.serializeValue(gen, value, rootType);
1515 } else {
1516 prov.serializeValue(gen, value);
1517 }
1518 }
1519 }
1520 }
1521