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         produces("application/json");
180         accept("application/json,text/json");
181         addBeanTypesJson = env("JsonSerializer.addBeanTypes", false);
182         escapeSolidus = env("JsonSerializer.escapeSolidus", false);
183         simpleAttrs = env("JsonSerializer.simpleAttrs", false);
184      }
185
186      /**
187       * Copy constructor.
188       *
189       * @param copyFrom The bean to copy from.
190       */
191      protected Builder(JsonSerializer copyFrom) {
192         super(copyFrom);
193         addBeanTypesJson = copyFrom.addBeanTypesJson;
194         escapeSolidus = copyFrom.escapeSolidus;
195         simpleAttrs = copyFrom.simpleAttrs;
196      }
197
198      /**
199       * Copy constructor.
200       *
201       * @param copyFrom The builder to copy from.
202       */
203      protected Builder(Builder copyFrom) {
204         super(copyFrom);
205         addBeanTypesJson = copyFrom.addBeanTypesJson;
206         escapeSolidus = copyFrom.escapeSolidus;
207         simpleAttrs = copyFrom.simpleAttrs;
208      }
209
210      @Override /* Context.Builder */
211      public Builder copy() {
212         return new Builder(this);
213      }
214
215      @Override /* Context.Builder */
216      public JsonSerializer build() {
217         return cache(CACHE).build(JsonSerializer.class);
218      }
219
220      @Override /* Context.Builder */
221      public HashKey hashKey() {
222         return HashKey.of(
223            super.hashKey(),
224            addBeanTypesJson,
225            escapeSolidus,
226            simpleAttrs
227         );
228      }
229
230      //-----------------------------------------------------------------------------------------------------------------
231      // Properties
232      //-----------------------------------------------------------------------------------------------------------------
233
234      /**
235       * Add <js>"_type"</js> properties when needed.
236       *
237       * <p>
238       * If <jk>true</jk>, then <js>"_type"</js> properties will be added to beans if their type cannot be inferred
239       * through reflection.
240       *
241       * <p>
242       * When present, this value overrides the {@link org.apache.juneau.serializer.Serializer.Builder#addBeanTypes()} setting and is
243       * provided to customize the behavior of specific serializers in a {@link SerializerSet}.
244       *
245       * @return This object.
246       */
247      @FluentSetter
248      public Builder addBeanTypesJson() {
249         return addBeanTypesJson(true);
250      }
251
252      /**
253       * Same as {@link #addBeanTypesJson()} but allows you to explicitly specify the value.
254       *
255       * @param value The value for this setting.
256       * @return This object.
257       */
258      @FluentSetter
259      public Builder addBeanTypesJson(boolean value) {
260         addBeanTypesJson = value;
261         return this;
262      }
263
264      /**
265       * Prefix solidus <js>'/'</js> characters with escapes.
266       *
267       * <p>
268       * If enabled, solidus (e.g. slash) characters should be escaped.
269       *
270       * <p>
271       * The JSON specification allows for either format.
272       * <br>However, if you're embedding JSON in an HTML script tag, this setting prevents confusion when trying to serialize
273       * <xt>&lt;\/script&gt;</xt>.
274       *
275       * <h5 class='section'>Example:</h5>
276       * <p class='bjava'>
277       *    <jc>// Create a JSON serializer that escapes solidus characters.</jc>
278       *    WriterSerializer <jv>serializer</jv> = JsonSerializer
279       *       .<jsm>create</jsm>()
280       *       .simple()
281       *       .escapeSolidus()
282       *       .build();
283       *
284       *    <jc>// Produces: "{foo:'&lt;\/bar&gt;'"</jc>
285       *    String <jv>json</jv> = <jv>serializer</jv>.serialize(JsonMap.<jsm>of</jsm>(<js>"foo"</js>, <js>"&lt;/bar&gt;"</js>);
286       * </p>
287       *
288       * @return This object.
289       */
290      @FluentSetter
291      public Builder escapeSolidus() {
292         return escapeSolidus(true);
293      }
294
295      /**
296       * Same as {@link #escapeSolidus()} but allows you to explicitly specify the value.
297       *
298       * @param value The value for this setting.
299       * @return This object.
300       */
301      @FluentSetter
302      public Builder escapeSolidus(boolean value) {
303         escapeSolidus = value;
304         return this;
305      }
306
307      /**
308       * Simple JSON attributes mode.
309       *
310       * <p>
311       * If enabled, JSON attribute names will only be quoted when necessary.
312       * <br>Otherwise, they are always quoted.
313       *
314       * <p>
315       * Attributes do not need to be quoted when they conform to the following:
316       * <ol class='spaced-list'>
317       *    <li>They start with an ASCII character or <js>'_'</js>.
318       *    <li>They contain only ASCII characters or numbers or <js>'_'</js>.
319       *    <li>They are not one of the following reserved words:
320       *       <p class='bcode'>
321       *    arguments, break, case, catch, class, const, continue, debugger, default,
322       *    delete, do, else, enum, eval, export, extends, false, finally, for, function,
323       *    if, implements, import, in, instanceof, interface, let, new, null, package,
324       *    private, protected, public, return, static, super, switch, this, throw,
325       *    true, try, typeof, var, void, while, with, undefined, yield
326       *       </p>
327       * </ol>
328       *
329       * <h5 class='section'>Example:</h5>
330       * <p class='bjava'>
331       *    <jc>// Create a JSON serializer in normal mode.</jc>
332       *    WriterSerializer <jv>serializer1</jv> = JsonSerializer
333       *       .<jsm>create</jsm>()
334       *       .build();
335       *
336       *    <jc>// Create a JSON serializer in simple mode.</jc>
337       *    WriterSerializer <jv>serializer2</jv> = JsonSerializer
338       *       .<jsm>create</jsm>()
339       *       .simpleAttrs()
340       *       .build();
341       *
342       *    JsonMap <jv>myMap</jv> = JsonMap.<jsm>of</jsm>(
343       *       <js>"foo"</js>, <js>"x1"</js>,
344       *       <js>"_bar"</js>, <js>"x2"</js>,
345       *       <js>" baz "</js>, <js>"x3"</js>,
346       *       <js>"123"</js>, <js>"x4"</js>,
347       *       <js>"return"</js>, <js>"x5"</js>,
348       *       <js>""</js>, <js>"x6"</js>
349       *  );
350       *
351       *    <jc>// Produces:</jc>
352       *    <jc>// {</jc>
353       *    <jc>//   "foo": "x1"</jc>
354       *    <jc>//   "_bar": "x2"</jc>
355       *    <jc>//   " baz ": "x3"</jc>
356       *    <jc>//   "123": "x4"</jc>
357       *    <jc>//   "return": "x5"</jc>
358       *    <jc>//   "": "x6"</jc>
359       *    <jc>// }</jc>
360       *    String <jv>json1</jv> = <jv>serializer1</jv>.serialize(<jv>myMap</jv>);
361       *
362       *    <jc>// Produces:</jc>
363       *    <jc>// {</jc>
364       *    <jc>//   foo: "x1"</jc>
365       *    <jc>//   _bar: "x2"</jc>
366       *    <jc>//   " baz ": "x3"</jc>
367       *    <jc>//   "123": "x4"</jc>
368       *    <jc>//   "return": "x5"</jc>
369       *    <jc>//   "": "x6"</jc>
370       *    <jc>// }</jc>
371       *    String <jv>json2</jv> = <jv>serializer2</jv>.serialize(<jv>myMap</jv>);
372       * </p>
373       *
374       * @return This object.
375       */
376      @FluentSetter
377      public Builder simpleAttrs() {
378         return simpleAttrs(true);
379      }
380
381      /**
382       * Same as {@link #simpleAttrs()} but allows you to explicitly specify the value.
383       *
384       * @param value The value for this setting.
385       * @return This object.
386       */
387      @FluentSetter
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      @FluentSetter
406      public Builder json5() {
407         return simpleAttrs().sq();
408      }
409
410      // <FluentSetters>
411
412      @Override /* GENERATED - org.apache.juneau.Context.Builder */
413      public Builder annotations(Annotation...values) {
414         super.annotations(values);
415         return this;
416      }
417
418      @Override /* GENERATED - org.apache.juneau.Context.Builder */
419      public Builder apply(AnnotationWorkList work) {
420         super.apply(work);
421         return this;
422      }
423
424      @Override /* GENERATED - org.apache.juneau.Context.Builder */
425      public Builder applyAnnotations(java.lang.Class<?>...fromClasses) {
426         super.applyAnnotations(fromClasses);
427         return this;
428      }
429
430      @Override /* GENERATED - org.apache.juneau.Context.Builder */
431      public Builder applyAnnotations(Method...fromMethods) {
432         super.applyAnnotations(fromMethods);
433         return this;
434      }
435
436      @Override /* GENERATED - org.apache.juneau.Context.Builder */
437      public Builder cache(Cache<HashKey,? extends org.apache.juneau.Context> value) {
438         super.cache(value);
439         return this;
440      }
441
442      @Override /* GENERATED - org.apache.juneau.Context.Builder */
443      public Builder debug() {
444         super.debug();
445         return this;
446      }
447
448      @Override /* GENERATED - org.apache.juneau.Context.Builder */
449      public Builder debug(boolean value) {
450         super.debug(value);
451         return this;
452      }
453
454      @Override /* GENERATED - org.apache.juneau.Context.Builder */
455      public Builder impl(Context value) {
456         super.impl(value);
457         return this;
458      }
459
460      @Override /* GENERATED - org.apache.juneau.Context.Builder */
461      public Builder type(Class<? extends org.apache.juneau.Context> value) {
462         super.type(value);
463         return this;
464      }
465
466      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
467      public Builder beanClassVisibility(Visibility value) {
468         super.beanClassVisibility(value);
469         return this;
470      }
471
472      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
473      public Builder beanConstructorVisibility(Visibility value) {
474         super.beanConstructorVisibility(value);
475         return this;
476      }
477
478      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
479      public Builder beanContext(BeanContext value) {
480         super.beanContext(value);
481         return this;
482      }
483
484      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
485      public Builder beanContext(BeanContext.Builder value) {
486         super.beanContext(value);
487         return this;
488      }
489
490      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
491      public Builder beanDictionary(java.lang.Class<?>...values) {
492         super.beanDictionary(values);
493         return this;
494      }
495
496      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
497      public Builder beanFieldVisibility(Visibility value) {
498         super.beanFieldVisibility(value);
499         return this;
500      }
501
502      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
503      public Builder beanInterceptor(Class<?> on, Class<? extends org.apache.juneau.swap.BeanInterceptor<?>> value) {
504         super.beanInterceptor(on, value);
505         return this;
506      }
507
508      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
509      public Builder beanMapPutReturnsOldValue() {
510         super.beanMapPutReturnsOldValue();
511         return this;
512      }
513
514      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
515      public Builder beanMethodVisibility(Visibility value) {
516         super.beanMethodVisibility(value);
517         return this;
518      }
519
520      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
521      public Builder beanProperties(Map<String,Object> values) {
522         super.beanProperties(values);
523         return this;
524      }
525
526      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
527      public Builder beanProperties(Class<?> beanClass, String properties) {
528         super.beanProperties(beanClass, properties);
529         return this;
530      }
531
532      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
533      public Builder beanProperties(String beanClassName, String properties) {
534         super.beanProperties(beanClassName, properties);
535         return this;
536      }
537
538      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
539      public Builder beanPropertiesExcludes(Map<String,Object> values) {
540         super.beanPropertiesExcludes(values);
541         return this;
542      }
543
544      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
545      public Builder beanPropertiesExcludes(Class<?> beanClass, String properties) {
546         super.beanPropertiesExcludes(beanClass, properties);
547         return this;
548      }
549
550      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
551      public Builder beanPropertiesExcludes(String beanClassName, String properties) {
552         super.beanPropertiesExcludes(beanClassName, properties);
553         return this;
554      }
555
556      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
557      public Builder beanPropertiesReadOnly(Map<String,Object> values) {
558         super.beanPropertiesReadOnly(values);
559         return this;
560      }
561
562      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
563      public Builder beanPropertiesReadOnly(Class<?> beanClass, String properties) {
564         super.beanPropertiesReadOnly(beanClass, properties);
565         return this;
566      }
567
568      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
569      public Builder beanPropertiesReadOnly(String beanClassName, String properties) {
570         super.beanPropertiesReadOnly(beanClassName, properties);
571         return this;
572      }
573
574      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
575      public Builder beanPropertiesWriteOnly(Map<String,Object> values) {
576         super.beanPropertiesWriteOnly(values);
577         return this;
578      }
579
580      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
581      public Builder beanPropertiesWriteOnly(Class<?> beanClass, String properties) {
582         super.beanPropertiesWriteOnly(beanClass, properties);
583         return this;
584      }
585
586      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
587      public Builder beanPropertiesWriteOnly(String beanClassName, String properties) {
588         super.beanPropertiesWriteOnly(beanClassName, properties);
589         return this;
590      }
591
592      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
593      public Builder beansRequireDefaultConstructor() {
594         super.beansRequireDefaultConstructor();
595         return this;
596      }
597
598      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
599      public Builder beansRequireSerializable() {
600         super.beansRequireSerializable();
601         return this;
602      }
603
604      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
605      public Builder beansRequireSettersForGetters() {
606         super.beansRequireSettersForGetters();
607         return this;
608      }
609
610      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
611      public Builder dictionaryOn(Class<?> on, java.lang.Class<?>...values) {
612         super.dictionaryOn(on, values);
613         return this;
614      }
615
616      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
617      public Builder disableBeansRequireSomeProperties() {
618         super.disableBeansRequireSomeProperties();
619         return this;
620      }
621
622      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
623      public Builder disableIgnoreMissingSetters() {
624         super.disableIgnoreMissingSetters();
625         return this;
626      }
627
628      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
629      public Builder disableIgnoreTransientFields() {
630         super.disableIgnoreTransientFields();
631         return this;
632      }
633
634      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
635      public Builder disableIgnoreUnknownNullBeanProperties() {
636         super.disableIgnoreUnknownNullBeanProperties();
637         return this;
638      }
639
640      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
641      public Builder disableInterfaceProxies() {
642         super.disableInterfaceProxies();
643         return this;
644      }
645
646      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
647      public <T> Builder example(Class<T> pojoClass, T o) {
648         super.example(pojoClass, o);
649         return this;
650      }
651
652      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
653      public <T> Builder example(Class<T> pojoClass, String json) {
654         super.example(pojoClass, json);
655         return this;
656      }
657
658      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
659      public Builder findFluentSetters() {
660         super.findFluentSetters();
661         return this;
662      }
663
664      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
665      public Builder findFluentSetters(Class<?> on) {
666         super.findFluentSetters(on);
667         return this;
668      }
669
670      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
671      public Builder ignoreInvocationExceptionsOnGetters() {
672         super.ignoreInvocationExceptionsOnGetters();
673         return this;
674      }
675
676      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
677      public Builder ignoreInvocationExceptionsOnSetters() {
678         super.ignoreInvocationExceptionsOnSetters();
679         return this;
680      }
681
682      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
683      public Builder ignoreUnknownBeanProperties() {
684         super.ignoreUnknownBeanProperties();
685         return this;
686      }
687
688      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
689      public Builder ignoreUnknownEnumValues() {
690         super.ignoreUnknownEnumValues();
691         return this;
692      }
693
694      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
695      public Builder implClass(Class<?> interfaceClass, Class<?> implClass) {
696         super.implClass(interfaceClass, implClass);
697         return this;
698      }
699
700      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
701      public Builder implClasses(Map<Class<?>,Class<?>> values) {
702         super.implClasses(values);
703         return this;
704      }
705
706      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
707      public Builder interfaceClass(Class<?> on, Class<?> value) {
708         super.interfaceClass(on, value);
709         return this;
710      }
711
712      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
713      public Builder interfaces(java.lang.Class<?>...value) {
714         super.interfaces(value);
715         return this;
716      }
717
718      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
719      public Builder locale(Locale value) {
720         super.locale(value);
721         return this;
722      }
723
724      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
725      public Builder mediaType(MediaType value) {
726         super.mediaType(value);
727         return this;
728      }
729
730      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
731      public Builder notBeanClasses(java.lang.Class<?>...values) {
732         super.notBeanClasses(values);
733         return this;
734      }
735
736      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
737      public Builder notBeanPackages(String...values) {
738         super.notBeanPackages(values);
739         return this;
740      }
741
742      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
743      public Builder propertyNamer(Class<? extends org.apache.juneau.PropertyNamer> value) {
744         super.propertyNamer(value);
745         return this;
746      }
747
748      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
749      public Builder propertyNamer(Class<?> on, Class<? extends org.apache.juneau.PropertyNamer> value) {
750         super.propertyNamer(on, value);
751         return this;
752      }
753
754      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
755      public Builder sortProperties() {
756         super.sortProperties();
757         return this;
758      }
759
760      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
761      public Builder sortProperties(java.lang.Class<?>...on) {
762         super.sortProperties(on);
763         return this;
764      }
765
766      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
767      public Builder stopClass(Class<?> on, Class<?> value) {
768         super.stopClass(on, value);
769         return this;
770      }
771
772      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
773      public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction) {
774         super.swap(normalClass, swappedClass, swapFunction);
775         return this;
776      }
777
778      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
779      public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction, ThrowingFunction<S,T> unswapFunction) {
780         super.swap(normalClass, swappedClass, swapFunction, unswapFunction);
781         return this;
782      }
783
784      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
785      public Builder swaps(java.lang.Class<?>...values) {
786         super.swaps(values);
787         return this;
788      }
789
790      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
791      public Builder timeZone(TimeZone value) {
792         super.timeZone(value);
793         return this;
794      }
795
796      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
797      public Builder typeName(Class<?> on, String value) {
798         super.typeName(on, value);
799         return this;
800      }
801
802      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
803      public Builder typePropertyName(String value) {
804         super.typePropertyName(value);
805         return this;
806      }
807
808      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
809      public Builder typePropertyName(Class<?> on, String value) {
810         super.typePropertyName(on, value);
811         return this;
812      }
813
814      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
815      public Builder useEnumNames() {
816         super.useEnumNames();
817         return this;
818      }
819
820      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
821      public Builder useJavaBeanIntrospector() {
822         super.useJavaBeanIntrospector();
823         return this;
824      }
825
826      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
827      public Builder detectRecursions() {
828         super.detectRecursions();
829         return this;
830      }
831
832      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
833      public Builder detectRecursions(boolean value) {
834         super.detectRecursions(value);
835         return this;
836      }
837
838      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
839      public Builder ignoreRecursions() {
840         super.ignoreRecursions();
841         return this;
842      }
843
844      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
845      public Builder ignoreRecursions(boolean value) {
846         super.ignoreRecursions(value);
847         return this;
848      }
849
850      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
851      public Builder initialDepth(int value) {
852         super.initialDepth(value);
853         return this;
854      }
855
856      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
857      public Builder maxDepth(int value) {
858         super.maxDepth(value);
859         return this;
860      }
861
862      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
863      public Builder accept(String value) {
864         super.accept(value);
865         return this;
866      }
867
868      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
869      public Builder addBeanTypes() {
870         super.addBeanTypes();
871         return this;
872      }
873
874      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
875      public Builder addBeanTypes(boolean value) {
876         super.addBeanTypes(value);
877         return this;
878      }
879
880      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
881      public Builder addRootType() {
882         super.addRootType();
883         return this;
884      }
885
886      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
887      public Builder addRootType(boolean value) {
888         super.addRootType(value);
889         return this;
890      }
891
892      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
893      public Builder keepNullProperties() {
894         super.keepNullProperties();
895         return this;
896      }
897
898      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
899      public Builder keepNullProperties(boolean value) {
900         super.keepNullProperties(value);
901         return this;
902      }
903
904      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
905      public Builder listener(Class<? extends org.apache.juneau.serializer.SerializerListener> value) {
906         super.listener(value);
907         return this;
908      }
909
910      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
911      public Builder produces(String value) {
912         super.produces(value);
913         return this;
914      }
915
916      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
917      public Builder sortCollections() {
918         super.sortCollections();
919         return this;
920      }
921
922      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
923      public Builder sortCollections(boolean value) {
924         super.sortCollections(value);
925         return this;
926      }
927
928      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
929      public Builder sortMaps() {
930         super.sortMaps();
931         return this;
932      }
933
934      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
935      public Builder sortMaps(boolean value) {
936         super.sortMaps(value);
937         return this;
938      }
939
940      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
941      public Builder trimEmptyCollections() {
942         super.trimEmptyCollections();
943         return this;
944      }
945
946      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
947      public Builder trimEmptyCollections(boolean value) {
948         super.trimEmptyCollections(value);
949         return this;
950      }
951
952      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
953      public Builder trimEmptyMaps() {
954         super.trimEmptyMaps();
955         return this;
956      }
957
958      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
959      public Builder trimEmptyMaps(boolean value) {
960         super.trimEmptyMaps(value);
961         return this;
962      }
963
964      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
965      public Builder trimStrings() {
966         super.trimStrings();
967         return this;
968      }
969
970      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
971      public Builder trimStrings(boolean value) {
972         super.trimStrings(value);
973         return this;
974      }
975
976      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
977      public Builder uriContext(UriContext value) {
978         super.uriContext(value);
979         return this;
980      }
981
982      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
983      public Builder uriRelativity(UriRelativity value) {
984         super.uriRelativity(value);
985         return this;
986      }
987
988      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
989      public Builder uriResolution(UriResolution value) {
990         super.uriResolution(value);
991         return this;
992      }
993
994      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
995      public Builder fileCharset(Charset value) {
996         super.fileCharset(value);
997         return this;
998      }
999
1000      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1001      public Builder maxIndent(int value) {
1002         super.maxIndent(value);
1003         return this;
1004      }
1005
1006      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1007      public Builder quoteChar(char value) {
1008         super.quoteChar(value);
1009         return this;
1010      }
1011
1012      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1013      public Builder quoteCharOverride(char value) {
1014         super.quoteCharOverride(value);
1015         return this;
1016      }
1017
1018      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1019      public Builder sq() {
1020         super.sq();
1021         return this;
1022      }
1023
1024      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1025      public Builder streamCharset(Charset value) {
1026         super.streamCharset(value);
1027         return this;
1028      }
1029
1030      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1031      public Builder useWhitespace() {
1032         super.useWhitespace();
1033         return this;
1034      }
1035
1036      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1037      public Builder useWhitespace(boolean value) {
1038         super.useWhitespace(value);
1039         return this;
1040      }
1041
1042      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1043      public Builder ws() {
1044         super.ws();
1045         return this;
1046      }
1047
1048      // </FluentSetters>
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}