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 */ ObjectWriter(ObjectMapper mapper, SerializationConfig config, JavaType rootType, PrettyPrinter pp)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 */ ObjectWriter(ObjectMapper mapper, SerializationConfig config)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 */ ObjectWriter(ObjectMapper mapper, SerializationConfig config, FormatSchema s)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 */ ObjectWriter(ObjectWriter base, SerializationConfig config, GeneratorSettings genSettings, Prefetch prefetch)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 */ ObjectWriter(ObjectWriter base, SerializationConfig config)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 */ ObjectWriter(ObjectWriter base, JsonFactory f)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 version()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 */ _new(ObjectWriter base, JsonFactory f)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 */ _new(ObjectWriter base, SerializationConfig config)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 */ _new(GeneratorSettings genSettings, Prefetch prefetch)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") _newSequenceWriter(boolean wrapInArray, JsonGenerator gen, boolean managedInput)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 */ with(SerializationFeature feature)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 */ with(SerializationFeature first, SerializationFeature... other)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 */ withFeatures(SerializationFeature... features)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 */ without(SerializationFeature feature)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 */ without(SerializationFeature first, SerializationFeature... other)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 */ withoutFeatures(SerializationFeature... features)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 */ with(JsonGenerator.Feature feature)326 public ObjectWriter with(JsonGenerator.Feature feature) { 327 return _new(this, _config.with(feature)); 328 } 329 330 /** 331 * @since 2.5 332 */ withFeatures(JsonGenerator.Feature... features)333 public ObjectWriter withFeatures(JsonGenerator.Feature... features) { 334 return _new(this, _config.withFeatures(features)); 335 } 336 337 /** 338 * @since 2.5 339 */ without(JsonGenerator.Feature feature)340 public ObjectWriter without(JsonGenerator.Feature feature) { 341 return _new(this, _config.without(feature)); 342 } 343 344 /** 345 * @since 2.5 346 */ withoutFeatures(JsonGenerator.Feature... features)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 */ with(StreamWriteFeature feature)360 public ObjectWriter with(StreamWriteFeature feature) { 361 return _new(this, _config.with(feature.mappedFeature())); 362 } 363 364 /** 365 * @since 2.11 366 */ without(StreamWriteFeature feature)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 */ with(FormatFeature feature)380 public ObjectWriter with(FormatFeature feature) { 381 return _new(this, _config.with(feature)); 382 } 383 384 /** 385 * @since 2.7 386 */ withFeatures(FormatFeature... features)387 public ObjectWriter withFeatures(FormatFeature... features) { 388 return _new(this, _config.withFeatures(features)); 389 } 390 391 /** 392 * @since 2.7 393 */ without(FormatFeature feature)394 public ObjectWriter without(FormatFeature feature) { 395 return _new(this, _config.without(feature)); 396 } 397 398 /** 399 * @since 2.7 400 */ withoutFeatures(FormatFeature... features)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 */ forType(JavaType rootType)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 */ forType(Class<?> rootType)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 */ forType(TypeReference<?> rootType)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 withType(JavaType rootType)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 withType(Class<?> rootType)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 withType(TypeReference<?> rootType)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 */ with(DateFormat df)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 */ withDefaultPrettyPrinter()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 */ with(FilterProvider filterProvider)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 */ with(PrettyPrinter pp)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 */ withRootName(String rootName)527 public ObjectWriter withRootName(String rootName) { 528 return _new(this, _config.withRootName(rootName)); 529 } 530 531 /** 532 * @since 2.6 533 */ withRootName(PropertyName rootName)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 */ withoutRootName()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 */ with(FormatSchema schema)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 withSchema(FormatSchema schema)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 */ withView(Class<?> view)580 public ObjectWriter withView(Class<?> view) { 581 return _new(this, _config.withView(view)); 582 } 583 with(Locale l)584 public ObjectWriter with(Locale l) { 585 return _new(this, _config.with(l)); 586 } 587 with(TimeZone tz)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 */ with(Base64Variant b64variant)598 public ObjectWriter with(Base64Variant b64variant) { 599 return _new(this, _config.with(b64variant)); 600 } 601 602 /** 603 * @since 2.3 604 */ with(CharacterEscapes escapes)605 public ObjectWriter with(CharacterEscapes escapes) { 606 return _new(_generatorSettings.with(escapes), _prefetch); 607 } 608 609 /** 610 * @since 2.3 611 */ with(JsonFactory f)612 public ObjectWriter with(JsonFactory f) { 613 return (f == _generatorFactory) ? this : _new(this, f); 614 } 615 616 /** 617 * @since 2.3 618 */ with(ContextAttributes attrs)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 */ withAttributes(Map<?,?> attrs)629 public ObjectWriter withAttributes(Map<?,?> attrs) { 630 return _new(this, _config.withAttributes(attrs)); 631 } 632 633 /** 634 * @since 2.3 635 */ withAttribute(Object key, Object value)636 public ObjectWriter withAttribute(Object key, Object value) { 637 return _new(this, _config.withAttribute(key, value)); 638 } 639 640 /** 641 * @since 2.3 642 */ withoutAttribute(Object key)643 public ObjectWriter withoutAttribute(Object key) { 644 return _new(this, _config.withoutAttribute(key)); 645 } 646 647 /** 648 * @since 2.5 649 */ withRootValueSeparator(String sep)650 public ObjectWriter withRootValueSeparator(String sep) { 651 return _new(_generatorSettings.withRootValueSeparator(sep), _prefetch); 652 } 653 654 /** 655 * @since 2.5 656 */ withRootValueSeparator(SerializableString sep)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 */ createGenerator(OutputStream out)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 */ createGenerator(OutputStream out, JsonEncoding enc)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 */ createGenerator(Writer w)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 */ createGenerator(File outputFile, JsonEncoding enc)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 */ createGenerator(DataOutput out)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 */ writeValues(File out)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 */ writeValues(JsonGenerator g)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 */ writeValues(Writer out)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 */ writeValues(OutputStream out)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 */ writeValues(DataOutput out)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 */ writeValuesAsArray(File out)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 */ writeValuesAsArray(JsonGenerator gen)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 */ writeValuesAsArray(Writer out)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 */ writeValuesAsArray(OutputStream out)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 */ writeValuesAsArray(DataOutput out)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 isEnabled(SerializationFeature f)907 public boolean isEnabled(SerializationFeature f) { 908 return _config.isEnabled(f); 909 } 910 isEnabled(MapperFeature f)911 public boolean isEnabled(MapperFeature f) { 912 return _config.isEnabled(f); 913 } 914 915 /** 916 * @since 2.9 917 */ 918 @Deprecated isEnabled(JsonParser.Feature f)919 public boolean isEnabled(JsonParser.Feature f) { 920 return _generatorFactory.isEnabled(f); 921 } 922 923 /** 924 * @since 2.9 925 */ isEnabled(JsonGenerator.Feature f)926 public boolean isEnabled(JsonGenerator.Feature f) { 927 return _generatorFactory.isEnabled(f); 928 } 929 930 /** 931 * @since 2.11 932 */ isEnabled(StreamWriteFeature f)933 public boolean isEnabled(StreamWriteFeature f) { 934 return _generatorFactory.isEnabled(f); 935 } 936 937 /** 938 * @since 2.2 939 */ getConfig()940 public SerializationConfig getConfig() { 941 return _config; 942 } 943 944 /** 945 * @since 2.2 946 */ getFactory()947 public JsonFactory getFactory() { 948 return _generatorFactory; 949 } 950 getTypeFactory()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 */ hasPrefetchedSerializer()963 public boolean hasPrefetchedSerializer() { 964 return _prefetch.hasSerializer(); 965 } 966 967 /** 968 * @since 2.3 969 */ getAttributes()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 */ writeValue(JsonGenerator g, Object value)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 */ writeValue(File resultFile, Object value)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 */ writeValue(OutputStream out, Object value)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 */ writeValue(Writer w, Object value)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 */ writeValue(DataOutput out, Object value)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") writeValueAsString(Object value)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") writeValueAsBytes(Object value)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 */ acceptJsonFormatVisitor(JavaType type, JsonFormatVisitorWrapper visitor)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 */ acceptJsonFormatVisitor(Class<?> type, JsonFormatVisitorWrapper visitor)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 canSerialize(Class<?> type)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 */ canSerialize(Class<?> type, AtomicReference<Throwable> cause)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 */ _serializerProvider()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 */ _verifySchemaType(FormatSchema schema)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 */ _writeValueAndClose(JsonGenerator gen, Object value)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 */ _writeCloseable(JsonGenerator gen, Object value)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 */ _configureGenerator(JsonGenerator gen)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 _assertNotNull(String paramName, Object src)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 GeneratorSettings(PrettyPrinter pp, FormatSchema sch, CharacterEscapes esc, SerializableString rootSep)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 with(PrettyPrinter pp)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 with(FormatSchema sch)1330 public GeneratorSettings with(FormatSchema sch) { 1331 return (schema == sch) ? this 1332 : new GeneratorSettings(prettyPrinter, sch, characterEscapes, rootValueSeparator); 1333 } 1334 with(CharacterEscapes esc)1335 public GeneratorSettings with(CharacterEscapes esc) { 1336 return (characterEscapes == esc) ? this 1337 : new GeneratorSettings(prettyPrinter, schema, esc, rootValueSeparator); 1338 } 1339 withRootValueSeparator(String sep)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 withRootValueSeparator(SerializableString sep)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 _rootValueSeparatorAsString()1367 private final String _rootValueSeparatorAsString() { 1368 return (rootValueSeparator == null) ? null : rootValueSeparator.getValue(); 1369 } 1370 1371 /** 1372 * @since 2.6 1373 */ initialize(JsonGenerator gen)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 Prefetch(JavaType rootT, JsonSerializer<Object> ser, TypeSerializer typeSer)1434 private Prefetch(JavaType rootT, 1435 JsonSerializer<Object> ser, TypeSerializer typeSer) 1436 { 1437 rootType = rootT; 1438 valueSerializer = ser; 1439 typeSerializer = typeSer; 1440 } 1441 forRootType(ObjectWriter parent, JavaType newType)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 getValueSerializer()1494 public final JsonSerializer<Object> getValueSerializer() { 1495 return valueSerializer; 1496 } 1497 getTypeSerializer()1498 public final TypeSerializer getTypeSerializer() { 1499 return typeSerializer; 1500 } 1501 hasSerializer()1502 public boolean hasSerializer() { 1503 return (valueSerializer != null) || (typeSerializer != null); 1504 } 1505 serialize(JsonGenerator gen, Object value, DefaultSerializerProvider prov)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