001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.json; 018 019import static org.apache.juneau.collections.JsonMap.*; 020import static org.apache.juneau.common.utils.Utils.*; 021 022import java.lang.annotation.*; 023import java.nio.charset.*; 024import java.util.*; 025import java.util.concurrent.*; 026 027import org.apache.juneau.*; 028import org.apache.juneau.collections.*; 029import org.apache.juneau.internal.*; 030import org.apache.juneau.serializer.*; 031import org.apache.juneau.utils.*; 032 033/** 034 * Serializes POJO models to JSON. 035 * 036 * <h5 class='topic'>Media types</h5> 037 * <p> 038 * Handles <c>Accept</c> types: <bc>application/json, text/json</bc> 039 * <p> 040 * Produces <c>Content-Type</c> types: <bc>application/json</bc> 041 * 042 * <h5 class='topic'>Description</h5> 043 * <p> 044 * The conversion is as follows... 045 * <ul class='spaced-list'> 046 * <li> 047 * Maps (e.g. {@link HashMap HashMaps}, {@link TreeMap TreeMaps}) are converted to JSON objects. 048 * <li> 049 * Collections (e.g. {@link HashSet HashSets}, {@link LinkedList LinkedLists}) and Java arrays are converted to 050 * JSON arrays. 051 * <li> 052 * {@link String Strings} are converted to JSON strings. 053 * <li> 054 * {@link Number Numbers} (e.g. {@link Integer}, {@link Long}, {@link Double}) are converted to JSON numbers. 055 * <li> 056 * {@link Boolean Booleans} are converted to JSON booleans. 057 * <li> 058 * {@code nulls} are converted to JSON nulls. 059 * <li> 060 * {@code arrays} are converted to JSON arrays. 061 * <li> 062 * {@code beans} are converted to JSON objects. 063 * </ul> 064 * 065 * <p> 066 * The types above are considered "JSON-primitive" object types. 067 * Any non-JSON-primitive object types are transformed into JSON-primitive object types through 068 * {@link org.apache.juneau.swap.ObjectSwap ObjectSwaps} associated through the 069 * {@link org.apache.juneau.BeanContext.Builder#swaps(Class...)} method. 070 * Several default transforms are provided for transforming Dates, Enums, Iterators, etc... 071 * 072 * <p> 073 * This serializer provides several serialization options. 074 * Typically, one of the predefined DEFAULT serializers will be sufficient. 075 * However, custom serializers can be constructed to fine-tune behavior. 076 * 077 * <h5 class='topic'>Behavior-specific subclasses</h5> 078 * <p> 079 * The following direct subclasses are provided for convenience: 080 * <ul class='spaced-list'> 081 * <li> 082 * {@link Json5Serializer} - Default serializer, single quotes, simple mode. 083 * <li> 084 * {@link Json5Serializer.Readable} - Default serializer, single quotes, simple mode, with whitespace. 085 * </ul> 086 * 087 * <h5 class='section'>Example:</h5> 088 * <p class='bjava'> 089 * <jc>// Use one of the default serializers to serialize a POJO</jc> 090 * String <jv>json</jv> = JsonSerializer.<jsf>DEFAULT</jsf>.serialize(<jv>someObject</jv>); 091 * 092 * <jc>// Create a custom serializer for lax syntax using single quote characters</jc> 093 * JsonSerializer <jv>serializer</jv> = JsonSerializer.<jsm>create</jsm>().simple().sq().build(); 094 * 095 * <jc>// Clone an existing serializer and modify it to use single-quotes</jc> 096 * <jv>serializer</jv> = JsonSerializer.<jsf>DEFAULT</jsf>.copy().sq().build(); 097 * 098 * <jc>// Serialize a POJO to JSON</jc> 099 * String <jv>json</jv> = <jv>serializer</jv>.serialize(<jv>someObject</jv>); 100 * </p> 101 * 102 * <h5 class='section'>Notes:</h5><ul> 103 * <li class='note'>This class is thread safe and reusable. 104 * </ul> 105 * 106 * <h5 class='section'>See Also:</h5><ul> 107 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JsonBasics">JSON Basics</a> 108 109 * </ul> 110 */ 111public class JsonSerializer extends WriterSerializer implements JsonMetaProvider { 112 113 //------------------------------------------------------------------------------------------------------------------- 114 // Static 115 //------------------------------------------------------------------------------------------------------------------- 116 117 /** Default serializer, all default settings.*/ 118 public static final JsonSerializer DEFAULT = new JsonSerializer(create()); 119 120 /** Default serializer, single quotes, {@link JsonSerializer.Builder#simpleAttrs() simple mode}, sorted bean properties. */ 121 public static final JsonSerializer DEFAULT_SORTED = new JsonSerializer(create().sortProperties()); 122 123 /** Default serializer, all default settings.*/ 124 public static final JsonSerializer DEFAULT_READABLE = new Readable(create()); 125 126 /** 127 * Creates a new builder for this object. 128 * 129 * @return A new builder. 130 */ 131 public static Builder create() { 132 return new Builder(); 133 } 134 135 //------------------------------------------------------------------------------------------------------------------- 136 // Static subclasses 137 //------------------------------------------------------------------------------------------------------------------- 138 139 /** Default serializer, with whitespace. */ 140 public static class Readable extends JsonSerializer { 141 142 /** 143 * Constructor. 144 * 145 * @param builder The builder for this object. 146 */ 147 public Readable(Builder builder) { 148 super(builder.useWhitespace()); 149 } 150 } 151 152 /** 153 * Default serializer, single quotes, simple mode, with whitespace and recursion detection. 154 * Note that recursion detection introduces a small performance penalty. 155 */ 156 public static class ReadableSafe extends JsonSerializer { 157 158 /** 159 * Constructor. 160 * 161 * @param builder The builder for this object. 162 */ 163 public ReadableSafe(Builder builder) { 164 super(builder.simpleAttrs().useWhitespace().detectRecursions()); 165 } 166 } 167 168 //------------------------------------------------------------------------------------------------------------------- 169 // Builder 170 //------------------------------------------------------------------------------------------------------------------- 171 172 /** 173 * Builder class. 174 */ 175 public static class Builder extends WriterSerializer.Builder { 176 177 private static final Cache<HashKey,JsonSerializer> CACHE = Cache.of(HashKey.class, JsonSerializer.class).build(); 178 179 boolean addBeanTypesJson, escapeSolidus, simpleAttrs; 180 181 /** 182 * Constructor, default settings. 183 */ 184 protected Builder() { 185 produces("application/json"); 186 accept("application/json,text/json"); 187 addBeanTypesJson = env("JsonSerializer.addBeanTypes", false); 188 escapeSolidus = env("JsonSerializer.escapeSolidus", false); 189 simpleAttrs = env("JsonSerializer.simpleAttrs", false); 190 } 191 192 /** 193 * Copy constructor. 194 * 195 * @param copyFrom The bean to copy from. 196 */ 197 protected Builder(JsonSerializer copyFrom) { 198 super(copyFrom); 199 addBeanTypesJson = copyFrom.addBeanTypesJson; 200 escapeSolidus = copyFrom.escapeSolidus; 201 simpleAttrs = copyFrom.simpleAttrs; 202 } 203 204 /** 205 * Copy constructor. 206 * 207 * @param copyFrom The builder to copy from. 208 */ 209 protected Builder(Builder copyFrom) { 210 super(copyFrom); 211 addBeanTypesJson = copyFrom.addBeanTypesJson; 212 escapeSolidus = copyFrom.escapeSolidus; 213 simpleAttrs = copyFrom.simpleAttrs; 214 } 215 216 @Override /* Context.Builder */ 217 public Builder copy() { 218 return new Builder(this); 219 } 220 221 @Override /* Context.Builder */ 222 public JsonSerializer build() { 223 return cache(CACHE).build(JsonSerializer.class); 224 } 225 226 @Override /* Context.Builder */ 227 public HashKey hashKey() { 228 return HashKey.of( 229 super.hashKey(), 230 addBeanTypesJson, 231 escapeSolidus, 232 simpleAttrs 233 ); 234 } 235 236 //----------------------------------------------------------------------------------------------------------------- 237 // Properties 238 //----------------------------------------------------------------------------------------------------------------- 239 240 /** 241 * Add <js>"_type"</js> properties when needed. 242 * 243 * <p> 244 * If <jk>true</jk>, then <js>"_type"</js> properties will be added to beans if their type cannot be inferred 245 * through reflection. 246 * 247 * <p> 248 * When present, this value overrides the {@link org.apache.juneau.serializer.Serializer.Builder#addBeanTypes()} setting and is 249 * provided to customize the behavior of specific serializers in a {@link SerializerSet}. 250 * 251 * @return This object. 252 */ 253 public Builder addBeanTypesJson() { 254 return addBeanTypesJson(true); 255 } 256 257 /** 258 * Same as {@link #addBeanTypesJson()} but allows you to explicitly specify the value. 259 * 260 * @param value The value for this setting. 261 * @return This object. 262 */ 263 public Builder addBeanTypesJson(boolean value) { 264 addBeanTypesJson = value; 265 return this; 266 } 267 268 /** 269 * Prefix solidus <js>'/'</js> characters with escapes. 270 * 271 * <p> 272 * If enabled, solidus (e.g. slash) characters should be escaped. 273 * 274 * <p> 275 * The JSON specification allows for either format. 276 * <br>However, if you're embedding JSON in an HTML script tag, this setting prevents confusion when trying to serialize 277 * <xt><\/script></xt>. 278 * 279 * <h5 class='section'>Example:</h5> 280 * <p class='bjava'> 281 * <jc>// Create a JSON serializer that escapes solidus characters.</jc> 282 * WriterSerializer <jv>serializer</jv> = JsonSerializer 283 * .<jsm>create</jsm>() 284 * .simple() 285 * .escapeSolidus() 286 * .build(); 287 * 288 * <jc>// Produces: "{foo:'<\/bar>'"</jc> 289 * String <jv>json</jv> = <jv>serializer</jv>.serialize(JsonMap.<jsm>of</jsm>(<js>"foo"</js>, <js>"</bar>"</js>); 290 * </p> 291 * 292 * @return This object. 293 */ 294 public Builder escapeSolidus() { 295 return escapeSolidus(true); 296 } 297 298 /** 299 * Same as {@link #escapeSolidus()} but allows you to explicitly specify the value. 300 * 301 * @param value The value for this setting. 302 * @return This object. 303 */ 304 public Builder escapeSolidus(boolean value) { 305 escapeSolidus = value; 306 return this; 307 } 308 309 /** 310 * Simple JSON attributes mode. 311 * 312 * <p> 313 * If enabled, JSON attribute names will only be quoted when necessary. 314 * <br>Otherwise, they are always quoted. 315 * 316 * <p> 317 * Attributes do not need to be quoted when they conform to the following: 318 * <ol class='spaced-list'> 319 * <li>They start with an ASCII character or <js>'_'</js>. 320 * <li>They contain only ASCII characters or numbers or <js>'_'</js>. 321 * <li>They are not one of the following reserved words: 322 * <p class='bcode'> 323 * arguments, break, case, catch, class, const, continue, debugger, default, 324 * delete, do, else, enum, eval, export, extends, false, finally, for, function, 325 * if, implements, import, in, instanceof, interface, let, new, null, package, 326 * private, protected, public, return, static, super, switch, this, throw, 327 * true, try, typeof, var, void, while, with, undefined, yield 328 * </p> 329 * </ol> 330 * 331 * <h5 class='section'>Example:</h5> 332 * <p class='bjava'> 333 * <jc>// Create a JSON serializer in normal mode.</jc> 334 * WriterSerializer <jv>serializer1</jv> = JsonSerializer 335 * .<jsm>create</jsm>() 336 * .build(); 337 * 338 * <jc>// Create a JSON serializer in simple mode.</jc> 339 * WriterSerializer <jv>serializer2</jv> = JsonSerializer 340 * .<jsm>create</jsm>() 341 * .simpleAttrs() 342 * .build(); 343 * 344 * JsonMap <jv>myMap</jv> = JsonMap.<jsm>of</jsm>( 345 * <js>"foo"</js>, <js>"x1"</js>, 346 * <js>"_bar"</js>, <js>"x2"</js>, 347 * <js>" baz "</js>, <js>"x3"</js>, 348 * <js>"123"</js>, <js>"x4"</js>, 349 * <js>"return"</js>, <js>"x5"</js>, 350 * <js>""</js>, <js>"x6"</js> 351 * ); 352 * 353 * <jc>// Produces:</jc> 354 * <jc>// {</jc> 355 * <jc>// "foo": "x1"</jc> 356 * <jc>// "_bar": "x2"</jc> 357 * <jc>// " baz ": "x3"</jc> 358 * <jc>// "123": "x4"</jc> 359 * <jc>// "return": "x5"</jc> 360 * <jc>// "": "x6"</jc> 361 * <jc>// }</jc> 362 * String <jv>json1</jv> = <jv>serializer1</jv>.serialize(<jv>myMap</jv>); 363 * 364 * <jc>// Produces:</jc> 365 * <jc>// {</jc> 366 * <jc>// foo: "x1"</jc> 367 * <jc>// _bar: "x2"</jc> 368 * <jc>// " baz ": "x3"</jc> 369 * <jc>// "123": "x4"</jc> 370 * <jc>// "return": "x5"</jc> 371 * <jc>// "": "x6"</jc> 372 * <jc>// }</jc> 373 * String <jv>json2</jv> = <jv>serializer2</jv>.serialize(<jv>myMap</jv>); 374 * </p> 375 * 376 * @return This object. 377 */ 378 public Builder simpleAttrs() { 379 return simpleAttrs(true); 380 } 381 382 /** 383 * Same as {@link #simpleAttrs()} but allows you to explicitly specify the value. 384 * 385 * @param value The value for this setting. 386 * @return This object. 387 */ 388 public Builder simpleAttrs(boolean value) { 389 simpleAttrs = value; 390 return this; 391 } 392 393 /** 394 * Simple JSON mode and single quote. 395 * 396 * <p> 397 * Shortcut for calling <c>simple().sq()</c>. 398 * 399 * <h5 class='section'>See Also:</h5><ul> 400 * <li class='jm'>{@link org.apache.juneau.serializer.WriterSerializer.Builder#quoteChar(char)} 401 * </ul> 402 * 403 * @return This object. 404 */ 405 public Builder json5() { 406 return simpleAttrs().sq(); 407 } 408 @Override /* Overridden from Builder */ 409 public Builder annotations(Annotation...values) { 410 super.annotations(values); 411 return this; 412 } 413 414 @Override /* Overridden from Builder */ 415 public Builder apply(AnnotationWorkList work) { 416 super.apply(work); 417 return this; 418 } 419 420 @Override /* Overridden from Builder */ 421 public Builder applyAnnotations(Object...from) { 422 super.applyAnnotations(from); 423 return this; 424 } 425 426 @Override /* Overridden from Builder */ 427 public Builder applyAnnotations(Class<?>...from) { 428 super.applyAnnotations(from); 429 return this; 430 } 431 432 @Override /* Overridden from Builder */ 433 public Builder cache(Cache<HashKey,? extends org.apache.juneau.Context> value) { 434 super.cache(value); 435 return this; 436 } 437 438 @Override /* Overridden from Builder */ 439 public Builder debug() { 440 super.debug(); 441 return this; 442 } 443 444 @Override /* Overridden from Builder */ 445 public Builder debug(boolean value) { 446 super.debug(value); 447 return this; 448 } 449 450 @Override /* Overridden from Builder */ 451 public Builder impl(Context value) { 452 super.impl(value); 453 return this; 454 } 455 456 @Override /* Overridden from Builder */ 457 public Builder type(Class<? extends org.apache.juneau.Context> value) { 458 super.type(value); 459 return this; 460 } 461 462 @Override /* Overridden from Builder */ 463 public Builder beanClassVisibility(Visibility value) { 464 super.beanClassVisibility(value); 465 return this; 466 } 467 468 @Override /* Overridden from Builder */ 469 public Builder beanConstructorVisibility(Visibility value) { 470 super.beanConstructorVisibility(value); 471 return this; 472 } 473 474 @Override /* Overridden from Builder */ 475 public Builder beanContext(BeanContext value) { 476 super.beanContext(value); 477 return this; 478 } 479 480 @Override /* Overridden from Builder */ 481 public Builder beanContext(BeanContext.Builder value) { 482 super.beanContext(value); 483 return this; 484 } 485 486 @Override /* Overridden from Builder */ 487 public Builder beanDictionary(java.lang.Class<?>...values) { 488 super.beanDictionary(values); 489 return this; 490 } 491 492 @Override /* Overridden from Builder */ 493 public Builder beanFieldVisibility(Visibility value) { 494 super.beanFieldVisibility(value); 495 return this; 496 } 497 498 @Override /* Overridden from Builder */ 499 public Builder beanInterceptor(Class<?> on, Class<? extends org.apache.juneau.swap.BeanInterceptor<?>> value) { 500 super.beanInterceptor(on, value); 501 return this; 502 } 503 504 @Override /* Overridden from Builder */ 505 public Builder beanMapPutReturnsOldValue() { 506 super.beanMapPutReturnsOldValue(); 507 return this; 508 } 509 510 @Override /* Overridden from Builder */ 511 public Builder beanMethodVisibility(Visibility value) { 512 super.beanMethodVisibility(value); 513 return this; 514 } 515 516 @Override /* Overridden from Builder */ 517 public Builder beanProperties(Map<String,Object> values) { 518 super.beanProperties(values); 519 return this; 520 } 521 522 @Override /* Overridden from Builder */ 523 public Builder beanProperties(Class<?> beanClass, String properties) { 524 super.beanProperties(beanClass, properties); 525 return this; 526 } 527 528 @Override /* Overridden from Builder */ 529 public Builder beanProperties(String beanClassName, String properties) { 530 super.beanProperties(beanClassName, properties); 531 return this; 532 } 533 534 @Override /* Overridden from Builder */ 535 public Builder beanPropertiesExcludes(Map<String,Object> values) { 536 super.beanPropertiesExcludes(values); 537 return this; 538 } 539 540 @Override /* Overridden from Builder */ 541 public Builder beanPropertiesExcludes(Class<?> beanClass, String properties) { 542 super.beanPropertiesExcludes(beanClass, properties); 543 return this; 544 } 545 546 @Override /* Overridden from Builder */ 547 public Builder beanPropertiesExcludes(String beanClassName, String properties) { 548 super.beanPropertiesExcludes(beanClassName, properties); 549 return this; 550 } 551 552 @Override /* Overridden from Builder */ 553 public Builder beanPropertiesReadOnly(Map<String,Object> values) { 554 super.beanPropertiesReadOnly(values); 555 return this; 556 } 557 558 @Override /* Overridden from Builder */ 559 public Builder beanPropertiesReadOnly(Class<?> beanClass, String properties) { 560 super.beanPropertiesReadOnly(beanClass, properties); 561 return this; 562 } 563 564 @Override /* Overridden from Builder */ 565 public Builder beanPropertiesReadOnly(String beanClassName, String properties) { 566 super.beanPropertiesReadOnly(beanClassName, properties); 567 return this; 568 } 569 570 @Override /* Overridden from Builder */ 571 public Builder beanPropertiesWriteOnly(Map<String,Object> values) { 572 super.beanPropertiesWriteOnly(values); 573 return this; 574 } 575 576 @Override /* Overridden from Builder */ 577 public Builder beanPropertiesWriteOnly(Class<?> beanClass, String properties) { 578 super.beanPropertiesWriteOnly(beanClass, properties); 579 return this; 580 } 581 582 @Override /* Overridden from Builder */ 583 public Builder beanPropertiesWriteOnly(String beanClassName, String properties) { 584 super.beanPropertiesWriteOnly(beanClassName, properties); 585 return this; 586 } 587 588 @Override /* Overridden from Builder */ 589 public Builder beansRequireDefaultConstructor() { 590 super.beansRequireDefaultConstructor(); 591 return this; 592 } 593 594 @Override /* Overridden from Builder */ 595 public Builder beansRequireSerializable() { 596 super.beansRequireSerializable(); 597 return this; 598 } 599 600 @Override /* Overridden from Builder */ 601 public Builder beansRequireSettersForGetters() { 602 super.beansRequireSettersForGetters(); 603 return this; 604 } 605 606 @Override /* Overridden from Builder */ 607 public Builder dictionaryOn(Class<?> on, java.lang.Class<?>...values) { 608 super.dictionaryOn(on, values); 609 return this; 610 } 611 612 @Override /* Overridden from Builder */ 613 public Builder disableBeansRequireSomeProperties() { 614 super.disableBeansRequireSomeProperties(); 615 return this; 616 } 617 618 @Override /* Overridden from Builder */ 619 public Builder disableIgnoreMissingSetters() { 620 super.disableIgnoreMissingSetters(); 621 return this; 622 } 623 624 @Override /* Overridden from Builder */ 625 public Builder disableIgnoreTransientFields() { 626 super.disableIgnoreTransientFields(); 627 return this; 628 } 629 630 @Override /* Overridden from Builder */ 631 public Builder disableIgnoreUnknownNullBeanProperties() { 632 super.disableIgnoreUnknownNullBeanProperties(); 633 return this; 634 } 635 636 @Override /* Overridden from Builder */ 637 public Builder disableInterfaceProxies() { 638 super.disableInterfaceProxies(); 639 return this; 640 } 641 642 @Override /* Overridden from Builder */ 643 public <T> Builder example(Class<T> pojoClass, T o) { 644 super.example(pojoClass, o); 645 return this; 646 } 647 648 @Override /* Overridden from Builder */ 649 public <T> Builder example(Class<T> pojoClass, String json) { 650 super.example(pojoClass, json); 651 return this; 652 } 653 654 @Override /* Overridden from Builder */ 655 public Builder findFluentSetters() { 656 super.findFluentSetters(); 657 return this; 658 } 659 660 @Override /* Overridden from Builder */ 661 public Builder findFluentSetters(Class<?> on) { 662 super.findFluentSetters(on); 663 return this; 664 } 665 666 @Override /* Overridden from Builder */ 667 public Builder ignoreInvocationExceptionsOnGetters() { 668 super.ignoreInvocationExceptionsOnGetters(); 669 return this; 670 } 671 672 @Override /* Overridden from Builder */ 673 public Builder ignoreInvocationExceptionsOnSetters() { 674 super.ignoreInvocationExceptionsOnSetters(); 675 return this; 676 } 677 678 @Override /* Overridden from Builder */ 679 public Builder ignoreUnknownBeanProperties() { 680 super.ignoreUnknownBeanProperties(); 681 return this; 682 } 683 684 @Override /* Overridden from Builder */ 685 public Builder ignoreUnknownEnumValues() { 686 super.ignoreUnknownEnumValues(); 687 return this; 688 } 689 690 @Override /* Overridden from Builder */ 691 public Builder implClass(Class<?> interfaceClass, Class<?> implClass) { 692 super.implClass(interfaceClass, implClass); 693 return this; 694 } 695 696 @Override /* Overridden from Builder */ 697 public Builder implClasses(Map<Class<?>,Class<?>> values) { 698 super.implClasses(values); 699 return this; 700 } 701 702 @Override /* Overridden from Builder */ 703 public Builder interfaceClass(Class<?> on, Class<?> value) { 704 super.interfaceClass(on, value); 705 return this; 706 } 707 708 @Override /* Overridden from Builder */ 709 public Builder interfaces(java.lang.Class<?>...value) { 710 super.interfaces(value); 711 return this; 712 } 713 714 @Override /* Overridden from Builder */ 715 public Builder locale(Locale value) { 716 super.locale(value); 717 return this; 718 } 719 720 @Override /* Overridden from Builder */ 721 public Builder mediaType(MediaType value) { 722 super.mediaType(value); 723 return this; 724 } 725 726 @Override /* Overridden from Builder */ 727 public Builder notBeanClasses(java.lang.Class<?>...values) { 728 super.notBeanClasses(values); 729 return this; 730 } 731 732 @Override /* Overridden from Builder */ 733 public Builder notBeanPackages(String...values) { 734 super.notBeanPackages(values); 735 return this; 736 } 737 738 @Override /* Overridden from Builder */ 739 public Builder propertyNamer(Class<? extends org.apache.juneau.PropertyNamer> value) { 740 super.propertyNamer(value); 741 return this; 742 } 743 744 @Override /* Overridden from Builder */ 745 public Builder propertyNamer(Class<?> on, Class<? extends org.apache.juneau.PropertyNamer> value) { 746 super.propertyNamer(on, value); 747 return this; 748 } 749 750 @Override /* Overridden from Builder */ 751 public Builder sortProperties() { 752 super.sortProperties(); 753 return this; 754 } 755 756 @Override /* Overridden from Builder */ 757 public Builder sortProperties(java.lang.Class<?>...on) { 758 super.sortProperties(on); 759 return this; 760 } 761 762 @Override /* Overridden from Builder */ 763 public Builder stopClass(Class<?> on, Class<?> value) { 764 super.stopClass(on, value); 765 return this; 766 } 767 768 @Override /* Overridden from Builder */ 769 public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction) { 770 super.swap(normalClass, swappedClass, swapFunction); 771 return this; 772 } 773 774 @Override /* Overridden from Builder */ 775 public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction, ThrowingFunction<S,T> unswapFunction) { 776 super.swap(normalClass, swappedClass, swapFunction, unswapFunction); 777 return this; 778 } 779 780 @Override /* Overridden from Builder */ 781 public Builder swaps(Object...values) { 782 super.swaps(values); 783 return this; 784 } 785 786 @Override /* Overridden from Builder */ 787 public Builder swaps(Class<?>...values) { 788 super.swaps(values); 789 return this; 790 } 791 792 @Override /* Overridden from Builder */ 793 public Builder timeZone(TimeZone value) { 794 super.timeZone(value); 795 return this; 796 } 797 798 @Override /* Overridden from Builder */ 799 public Builder typeName(Class<?> on, String value) { 800 super.typeName(on, value); 801 return this; 802 } 803 804 @Override /* Overridden from Builder */ 805 public Builder typePropertyName(String value) { 806 super.typePropertyName(value); 807 return this; 808 } 809 810 @Override /* Overridden from Builder */ 811 public Builder typePropertyName(Class<?> on, String value) { 812 super.typePropertyName(on, value); 813 return this; 814 } 815 816 @Override /* Overridden from Builder */ 817 public Builder useEnumNames() { 818 super.useEnumNames(); 819 return this; 820 } 821 822 @Override /* Overridden from Builder */ 823 public Builder useJavaBeanIntrospector() { 824 super.useJavaBeanIntrospector(); 825 return this; 826 } 827 828 @Override /* Overridden from Builder */ 829 public Builder detectRecursions() { 830 super.detectRecursions(); 831 return this; 832 } 833 834 @Override /* Overridden from Builder */ 835 public Builder detectRecursions(boolean value) { 836 super.detectRecursions(value); 837 return this; 838 } 839 840 @Override /* Overridden from Builder */ 841 public Builder ignoreRecursions() { 842 super.ignoreRecursions(); 843 return this; 844 } 845 846 @Override /* Overridden from Builder */ 847 public Builder ignoreRecursions(boolean value) { 848 super.ignoreRecursions(value); 849 return this; 850 } 851 852 @Override /* Overridden from Builder */ 853 public Builder initialDepth(int value) { 854 super.initialDepth(value); 855 return this; 856 } 857 858 @Override /* Overridden from Builder */ 859 public Builder maxDepth(int value) { 860 super.maxDepth(value); 861 return this; 862 } 863 864 @Override /* Overridden from Builder */ 865 public Builder accept(String value) { 866 super.accept(value); 867 return this; 868 } 869 870 @Override /* Overridden from Builder */ 871 public Builder addBeanTypes() { 872 super.addBeanTypes(); 873 return this; 874 } 875 876 @Override /* Overridden from Builder */ 877 public Builder addBeanTypes(boolean value) { 878 super.addBeanTypes(value); 879 return this; 880 } 881 882 @Override /* Overridden from Builder */ 883 public Builder addRootType() { 884 super.addRootType(); 885 return this; 886 } 887 888 @Override /* Overridden from Builder */ 889 public Builder addRootType(boolean value) { 890 super.addRootType(value); 891 return this; 892 } 893 894 @Override /* Overridden from Builder */ 895 public Builder keepNullProperties() { 896 super.keepNullProperties(); 897 return this; 898 } 899 900 @Override /* Overridden from Builder */ 901 public Builder keepNullProperties(boolean value) { 902 super.keepNullProperties(value); 903 return this; 904 } 905 906 @Override /* Overridden from Builder */ 907 public Builder listener(Class<? extends org.apache.juneau.serializer.SerializerListener> value) { 908 super.listener(value); 909 return this; 910 } 911 912 @Override /* Overridden from Builder */ 913 public Builder produces(String value) { 914 super.produces(value); 915 return this; 916 } 917 918 @Override /* Overridden from Builder */ 919 public Builder sortCollections() { 920 super.sortCollections(); 921 return this; 922 } 923 924 @Override /* Overridden from Builder */ 925 public Builder sortCollections(boolean value) { 926 super.sortCollections(value); 927 return this; 928 } 929 930 @Override /* Overridden from Builder */ 931 public Builder sortMaps() { 932 super.sortMaps(); 933 return this; 934 } 935 936 @Override /* Overridden from Builder */ 937 public Builder sortMaps(boolean value) { 938 super.sortMaps(value); 939 return this; 940 } 941 942 @Override /* Overridden from Builder */ 943 public Builder trimEmptyCollections() { 944 super.trimEmptyCollections(); 945 return this; 946 } 947 948 @Override /* Overridden from Builder */ 949 public Builder trimEmptyCollections(boolean value) { 950 super.trimEmptyCollections(value); 951 return this; 952 } 953 954 @Override /* Overridden from Builder */ 955 public Builder trimEmptyMaps() { 956 super.trimEmptyMaps(); 957 return this; 958 } 959 960 @Override /* Overridden from Builder */ 961 public Builder trimEmptyMaps(boolean value) { 962 super.trimEmptyMaps(value); 963 return this; 964 } 965 966 @Override /* Overridden from Builder */ 967 public Builder trimStrings() { 968 super.trimStrings(); 969 return this; 970 } 971 972 @Override /* Overridden from Builder */ 973 public Builder trimStrings(boolean value) { 974 super.trimStrings(value); 975 return this; 976 } 977 978 @Override /* Overridden from Builder */ 979 public Builder uriContext(UriContext value) { 980 super.uriContext(value); 981 return this; 982 } 983 984 @Override /* Overridden from Builder */ 985 public Builder uriRelativity(UriRelativity value) { 986 super.uriRelativity(value); 987 return this; 988 } 989 990 @Override /* Overridden from Builder */ 991 public Builder uriResolution(UriResolution value) { 992 super.uriResolution(value); 993 return this; 994 } 995 996 @Override /* Overridden from Builder */ 997 public Builder fileCharset(Charset value) { 998 super.fileCharset(value); 999 return this; 1000 } 1001 1002 @Override /* Overridden from Builder */ 1003 public Builder maxIndent(int value) { 1004 super.maxIndent(value); 1005 return this; 1006 } 1007 1008 @Override /* Overridden from Builder */ 1009 public Builder quoteChar(char value) { 1010 super.quoteChar(value); 1011 return this; 1012 } 1013 1014 @Override /* Overridden from Builder */ 1015 public Builder quoteCharOverride(char value) { 1016 super.quoteCharOverride(value); 1017 return this; 1018 } 1019 1020 @Override /* Overridden from Builder */ 1021 public Builder sq() { 1022 super.sq(); 1023 return this; 1024 } 1025 1026 @Override /* Overridden from Builder */ 1027 public Builder streamCharset(Charset value) { 1028 super.streamCharset(value); 1029 return this; 1030 } 1031 1032 @Override /* Overridden from Builder */ 1033 public Builder useWhitespace() { 1034 super.useWhitespace(); 1035 return this; 1036 } 1037 1038 @Override /* Overridden from Builder */ 1039 public Builder useWhitespace(boolean value) { 1040 super.useWhitespace(value); 1041 return this; 1042 } 1043 1044 @Override /* Overridden from Builder */ 1045 public Builder ws() { 1046 super.ws(); 1047 return this; 1048 } 1049 } 1050 1051 //------------------------------------------------------------------------------------------------------------------- 1052 // Instance 1053 //------------------------------------------------------------------------------------------------------------------- 1054 1055 final boolean addBeanTypesJson, escapeSolidus, simpleAttrs; 1056 1057 private final boolean addBeanTypes; 1058 private final Map<ClassMeta<?>,JsonClassMeta> jsonClassMetas = new ConcurrentHashMap<>(); 1059 private final Map<BeanPropertyMeta,JsonBeanPropertyMeta> jsonBeanPropertyMetas = new ConcurrentHashMap<>(); 1060 1061 private volatile JsonSchemaSerializer schemaSerializer; 1062 1063 /** 1064 * Constructor. 1065 * 1066 * @param builder The builder for this object. 1067 */ 1068 public JsonSerializer(Builder builder) { 1069 super(builder); 1070 addBeanTypesJson = builder.addBeanTypesJson; 1071 simpleAttrs = builder.simpleAttrs; 1072 escapeSolidus = builder.escapeSolidus; 1073 1074 addBeanTypes = addBeanTypesJson || super.isAddBeanTypes(); 1075 } 1076 1077 @Override /* Context */ 1078 public Builder copy() { 1079 return new Builder(this); 1080 } 1081 1082 @Override /* Context */ 1083 public JsonSerializerSession.Builder createSession() { 1084 return JsonSerializerSession.create(this); 1085 } 1086 1087 @Override /* Context */ 1088 public JsonSerializerSession getSession() { 1089 return createSession().build(); 1090 } 1091 1092 /** 1093 * Returns the schema serializer based on the settings of this serializer. 1094 * 1095 * <p> 1096 * Note that this method creates a builder initialized to all default settings, whereas {@link #copy()} copies 1097 * the settings of the object called on. 1098 * 1099 * @return The schema serializer. 1100 */ 1101 public JsonSchemaSerializer getSchemaSerializer() { 1102 if (schemaSerializer == null) 1103 schemaSerializer = JsonSchemaSerializer.create().beanContext(getBeanContext()).build(); 1104 return schemaSerializer; 1105 } 1106 1107 //----------------------------------------------------------------------------------------------------------------- 1108 // Extended metadata 1109 //----------------------------------------------------------------------------------------------------------------- 1110 1111 @Override /* JsonMetaProvider */ 1112 public JsonClassMeta getJsonClassMeta(ClassMeta<?> cm) { 1113 JsonClassMeta m = jsonClassMetas.get(cm); 1114 if (m == null) { 1115 m = new JsonClassMeta(cm, this); 1116 jsonClassMetas.put(cm, m); 1117 } 1118 return m; 1119 } 1120 1121 @Override /* JsonMetaProvider */ 1122 public JsonBeanPropertyMeta getJsonBeanPropertyMeta(BeanPropertyMeta bpm) { 1123 if (bpm == null) 1124 return JsonBeanPropertyMeta.DEFAULT; 1125 JsonBeanPropertyMeta m = jsonBeanPropertyMetas.get(bpm); 1126 if (m == null) { 1127 m = new JsonBeanPropertyMeta(bpm.getDelegateFor(), this); 1128 jsonBeanPropertyMetas.put(bpm, m); 1129 } 1130 return m; 1131 } 1132 1133 //----------------------------------------------------------------------------------------------------------------- 1134 // Properties 1135 //----------------------------------------------------------------------------------------------------------------- 1136 1137 /** 1138 * Add <js>"_type"</js> properties when needed. 1139 * 1140 * @see Builder#addBeanTypesJson() 1141 * @return 1142 * <jk>true</jk> if <js>"_type"</js> properties will be added to beans if their type cannot be inferred 1143 * through reflection. 1144 */ 1145 @Override 1146 protected final boolean isAddBeanTypes() { 1147 return addBeanTypes; 1148 } 1149 1150 /** 1151 * Prefix solidus <js>'/'</js> characters with escapes. 1152 * 1153 * @see Builder#escapeSolidus() 1154 * @return 1155 * <jk>true</jk> if solidus (e.g. slash) characters should be escaped. 1156 */ 1157 protected final boolean isEscapeSolidus() { 1158 return escapeSolidus; 1159 } 1160 1161 /** 1162 * Simple JSON mode. 1163 * 1164 * @see Builder#simpleAttrs() 1165 * @return 1166 * <jk>true</jk> if JSON attribute names will only be quoted when necessary. 1167 * <br>Otherwise, they are always quoted. 1168 */ 1169 protected final boolean isSimpleAttrs() { 1170 return simpleAttrs; 1171 } 1172 1173 //----------------------------------------------------------------------------------------------------------------- 1174 // Other methods 1175 //----------------------------------------------------------------------------------------------------------------- 1176 1177 @Override /* Context */ 1178 protected JsonMap properties() { 1179 return filteredMap("simpleAttrs", simpleAttrs, "escapeSolidus", escapeSolidus, "addBeanTypesJson", addBeanTypesJson); 1180 } 1181}