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