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