001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.json;
018
019import static org.apache.juneau.collections.JsonMap.*;
020
021import java.lang.annotation.*;
022import java.nio.charset.*;
023import java.util.*;
024import java.util.concurrent.*;
025
026import org.apache.juneau.*;
027import org.apache.juneau.annotation.*;
028import org.apache.juneau.collections.*;
029import org.apache.juneau.internal.*;
030import org.apache.juneau.jsonschema.*;
031import org.apache.juneau.utils.*;
032
033/**
034 * Serializes POJO metadata to HTTP responses as JSON-Schema.
035 *
036 * <h5 class='topic'>Media types</h5>
037 *
038 * Handles <c>Accept</c> types:  <bc>application/json+schema, text/json+schema</bc>
039 * <p>
040 * Produces <c>Content-Type</c> types:  <bc>application/json</bc>
041 *
042 * <h5 class='topic'>Description</h5>
043 *
044 * Produces the JSON-schema for the JSON produced by the {@link JsonSerializer} class with the same properties.
045 *
046 * <h5 class='section'>Notes:</h5><ul>
047 *    <li class='note'>This class is thread safe and reusable.
048 * </ul>
049 *
050 * <h5 class='section'>See Also:</h5><ul>
051 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JsonBasics">JSON Basics</a>
052
053 * </ul>
054 */
055public class JsonSchemaSerializer extends JsonSerializer implements JsonSchemaMetaProvider {
056
057   //-------------------------------------------------------------------------------------------------------------------
058   // Static
059   //-------------------------------------------------------------------------------------------------------------------
060
061   /** Default serializer, all default settings.*/
062   public static final JsonSchemaSerializer DEFAULT = new JsonSchemaSerializer(create());
063
064   /** Default serializer, all default settings.*/
065   public static final JsonSchemaSerializer DEFAULT_READABLE = new Readable(create());
066
067   /** Default serializer, single quotes, simple mode. */
068   public static final JsonSchemaSerializer DEFAULT_SIMPLE = new Simple(create());
069
070   /** Default serializer, single quotes, simple mode, with whitespace. */
071   public static final JsonSchemaSerializer DEFAULT_SIMPLE_READABLE = new SimpleReadable(create());
072
073   /**
074    * Creates a new builder for this object.
075    *
076    * @return A new builder.
077    */
078   public static Builder create() {
079      return new Builder();
080   }
081
082   //-------------------------------------------------------------------------------------------------------------------
083   // Static subclasses
084   //-------------------------------------------------------------------------------------------------------------------
085
086   /** Default serializer, with whitespace. */
087   public static class Readable extends JsonSchemaSerializer {
088
089      /**
090       * Constructor.
091       *
092       * @param builder The builder for this object.
093       */
094      public Readable(Builder builder) {
095         super(builder.useWhitespace());
096      }
097   }
098
099   /** Default serializer, single quotes, simple mode. */
100   public static class Simple extends JsonSchemaSerializer {
101
102      /**
103       * Constructor.
104       *
105       * @param builder The builder for this object.
106       */
107      public Simple(Builder builder) {
108         super(builder.simpleAttrs().quoteChar('\''));
109      }
110   }
111
112   /** Default serializer, single quotes, simple mode, with whitespace. */
113   public static class SimpleReadable extends JsonSchemaSerializer {
114
115      /**
116       * Constructor.
117       *
118       * @param builder The builder for this object.
119       */
120      public SimpleReadable(Builder builder) {
121         super(builder.simpleAttrs().quoteChar('\'').useWhitespace());
122      }
123   }
124
125   //-------------------------------------------------------------------------------------------------------------------
126   // Builder
127   //-------------------------------------------------------------------------------------------------------------------
128
129   /**
130    * Builder class.
131    */
132   public static class Builder extends JsonSerializer.Builder {
133
134      private static final Cache<HashKey,JsonSchemaSerializer> CACHE = Cache.of(HashKey.class, JsonSchemaSerializer.class).build();
135
136      JsonSchemaGenerator.Builder generatorBuilder;
137
138      /**
139       * Constructor, default settings.
140       */
141      protected Builder() {
142         produces("application/json");
143         accept("application/json+schema,text/json+schema");
144         generatorBuilder = JsonSchemaGenerator.create().beanContext(beanContext());
145      }
146
147      /**
148       * Copy constructor.
149       *
150       * @param copyFrom The bean to copy from.
151       */
152      protected Builder(JsonSchemaSerializer copyFrom) {
153         super(copyFrom);
154         generatorBuilder = copyFrom.generator.copy().beanContext(beanContext());
155      }
156
157      /**
158       * Copy constructor.
159       *
160       * @param copyFrom The builder to copy from.
161       */
162      protected Builder(Builder copyFrom) {
163         super(copyFrom);
164         generatorBuilder = copyFrom.generatorBuilder.copy().beanContext(beanContext());
165      }
166
167      @Override /* Context.Builder */
168      public Builder copy() {
169         return new Builder(this);
170      }
171
172      @Override /* Context.Builder */
173      public JsonSchemaSerializer build() {
174         return cache(CACHE).build(JsonSchemaSerializer.class);
175      }
176
177      @Override /* Context.Builder */
178      public HashKey hashKey() {
179         return HashKey.of(
180            super.hashKey(),
181            generatorBuilder.hashKey()
182         );
183      }
184
185      //-----------------------------------------------------------------------------------------------------------------
186      // Properties
187      //-----------------------------------------------------------------------------------------------------------------
188
189      /**
190       * <i><l>JsonSchemaSerializer</l> configuration property:&emsp;</i>  Add descriptions.
191       *
192       * <p>
193       * Identifies which categories of types that descriptions should be automatically added to generated schemas.
194       * <p>
195       * The description is the result of calling {@link ClassMeta#getFullName()}.
196       *
197       * <h5 class='section'>See Also:</h5><ul>
198       *    <li class='jm'>{@link org.apache.juneau.jsonschema.JsonSchemaGenerator.Builder#addDescriptionsTo(TypeCategory...)}
199       * </ul>
200       *
201       * @param values
202       *    The values to add to this setting.
203       *    <br>The default is an empty string.
204       * @return This object.
205       */
206      public Builder addDescriptionsTo(TypeCategory...values) {
207         generatorBuilder.addDescriptionsTo(values);
208         return this;
209      }
210
211      /**
212       * <i><l>JsonSchemaSerializer</l> configuration property:&emsp;</i>  Add examples.
213       *
214       * <p>
215       * Identifies which categories of types that examples should be automatically added to generated schemas.
216       * <p>
217       * The examples come from calling {@link ClassMeta#getExample(BeanSession,JsonParserSession)} which in turn gets examples
218       * from the following:
219       * <ul class='javatree'>
220       *    <li class='ja'>{@link Example}
221       *    <li class='ja'>{@link Marshalled#example() Marshalled(example)}
222       * </ul>
223       *
224       * <h5 class='section'>See Also:</h5><ul>
225       *    <li class='jm'>{@link org.apache.juneau.jsonschema.JsonSchemaGenerator.Builder#addExamplesTo(TypeCategory...)}
226       * </ul>
227       *
228       * @param values
229       *    The values to add to this setting.
230       *    <br>The default is an empty string.
231       * @return This object.
232       */
233      public Builder addExamplesTo(TypeCategory...values) {
234         generatorBuilder.addExamplesTo(values);
235         return this;
236      }
237
238      /**
239       * <i><l>JsonSchemaSerializer</l> configuration property:&emsp;</i>  Allow nested descriptions.
240       *
241       * <p>
242       * Identifies whether nested descriptions are allowed in schema definitions.
243       *
244       * <h5 class='section'>See Also:</h5><ul>
245       *    <li class='jm'>{@link org.apache.juneau.jsonschema.JsonSchemaGenerator.Builder#allowNestedDescriptions()}
246       * </ul>
247       *
248       * @return This object.
249       */
250      public Builder allowNestedDescriptions() {
251         generatorBuilder.allowNestedDescriptions();
252         return this;
253      }
254
255      /**
256       * <i><l>JsonSchemaSerializer</l> configuration property:&emsp;</i>  Allow nested examples.
257       *
258       * <p>
259       * Identifies whether nested examples are allowed in schema definitions.
260       *
261       * <h5 class='section'>See Also:</h5><ul>
262       *    <li class='jm'>{@link org.apache.juneau.jsonschema.JsonSchemaGenerator.Builder#allowNestedExamples()}
263       * </ul>
264       *
265       * @return This object.
266       */
267      public Builder allowNestedExamples() {
268         generatorBuilder.allowNestedExamples();
269         return this;
270      }
271
272      /**
273       * <i><l>JsonSchemaSerializer</l> configuration property:&emsp;</i>  Schema definition mapper.
274       *
275       * <p>
276       * Interface to use for converting Bean classes to definition IDs and URIs.
277       * <p>
278       * Used primarily for defining common definition sections for beans in Swagger JSON.
279       * <p>
280       * This setting is ignored if {@link org.apache.juneau.jsonschema.JsonSchemaGenerator.Builder#useBeanDefs()} is not enabled.
281       *
282       * <h5 class='section'>See Also:</h5><ul>
283       *    <li class='jm'>{@link org.apache.juneau.jsonschema.JsonSchemaGenerator.Builder#beanDefMapper(Class)}
284       * </ul>
285       *
286       * @param value
287       *    The new value for this property.
288       *    <br>The default is {@link org.apache.juneau.jsonschema.BasicBeanDefMapper}.
289       * @return This object.
290       */
291      public Builder beanDefMapper(Class<? extends BeanDefMapper> value) {
292         generatorBuilder.beanDefMapper(value);
293         return this;
294      }
295
296      /**
297       * <i><l>JsonSchemaSerializer</l> configuration property:&emsp;</i>  Use bean definitions.
298       *
299       * <p>
300       * When enabled, schemas on beans will be serialized as the following:
301       * <p class='bjson'>
302       *    {
303       *       type: <js>'object'</js>,
304       *       <js>'$ref'</js>: <js>'#/definitions/TypeId'</js>
305       *    }
306       * </p>
307       *
308       * @return This object.
309       */
310      public Builder useBeanDefs() {
311         generatorBuilder.useBeanDefs();
312         return this;
313      }
314      @Override /* Overridden from Builder */
315      public Builder annotations(Annotation...values) {
316         super.annotations(values);
317         return this;
318      }
319
320      @Override /* Overridden from Builder */
321      public Builder apply(AnnotationWorkList work) {
322         super.apply(work);
323         return this;
324      }
325
326      @Override /* Overridden from Builder */
327      public Builder applyAnnotations(Object...from) {
328         super.applyAnnotations(from);
329         return this;
330      }
331
332      @Override /* Overridden from Builder */
333      public Builder applyAnnotations(Class<?>...from) {
334         super.applyAnnotations(from);
335         return this;
336      }
337
338      @Override /* Overridden from Builder */
339      public Builder cache(Cache<HashKey,? extends org.apache.juneau.Context> value) {
340         super.cache(value);
341         return this;
342      }
343
344      @Override /* Overridden from Builder */
345      public Builder debug() {
346         super.debug();
347         return this;
348      }
349
350      @Override /* Overridden from Builder */
351      public Builder debug(boolean value) {
352         super.debug(value);
353         return this;
354      }
355
356      @Override /* Overridden from Builder */
357      public Builder impl(Context value) {
358         super.impl(value);
359         return this;
360      }
361
362      @Override /* Overridden from Builder */
363      public Builder type(Class<? extends org.apache.juneau.Context> value) {
364         super.type(value);
365         return this;
366      }
367
368      @Override /* Overridden from Builder */
369      public Builder beanClassVisibility(Visibility value) {
370         super.beanClassVisibility(value);
371         return this;
372      }
373
374      @Override /* Overridden from Builder */
375      public Builder beanConstructorVisibility(Visibility value) {
376         super.beanConstructorVisibility(value);
377         return this;
378      }
379
380      @Override /* Overridden from Builder */
381      public Builder beanContext(BeanContext value) {
382         super.beanContext(value);
383         return this;
384      }
385
386      @Override /* Overridden from Builder */
387      public Builder beanContext(BeanContext.Builder value) {
388         super.beanContext(value);
389         return this;
390      }
391
392      @Override /* Overridden from Builder */
393      public Builder beanDictionary(java.lang.Class<?>...values) {
394         super.beanDictionary(values);
395         return this;
396      }
397
398      @Override /* Overridden from Builder */
399      public Builder beanFieldVisibility(Visibility value) {
400         super.beanFieldVisibility(value);
401         return this;
402      }
403
404      @Override /* Overridden from Builder */
405      public Builder beanInterceptor(Class<?> on, Class<? extends org.apache.juneau.swap.BeanInterceptor<?>> value) {
406         super.beanInterceptor(on, value);
407         return this;
408      }
409
410      @Override /* Overridden from Builder */
411      public Builder beanMapPutReturnsOldValue() {
412         super.beanMapPutReturnsOldValue();
413         return this;
414      }
415
416      @Override /* Overridden from Builder */
417      public Builder beanMethodVisibility(Visibility value) {
418         super.beanMethodVisibility(value);
419         return this;
420      }
421
422      @Override /* Overridden from Builder */
423      public Builder beanProperties(Map<String,Object> values) {
424         super.beanProperties(values);
425         return this;
426      }
427
428      @Override /* Overridden from Builder */
429      public Builder beanProperties(Class<?> beanClass, String properties) {
430         super.beanProperties(beanClass, properties);
431         return this;
432      }
433
434      @Override /* Overridden from Builder */
435      public Builder beanProperties(String beanClassName, String properties) {
436         super.beanProperties(beanClassName, properties);
437         return this;
438      }
439
440      @Override /* Overridden from Builder */
441      public Builder beanPropertiesExcludes(Map<String,Object> values) {
442         super.beanPropertiesExcludes(values);
443         return this;
444      }
445
446      @Override /* Overridden from Builder */
447      public Builder beanPropertiesExcludes(Class<?> beanClass, String properties) {
448         super.beanPropertiesExcludes(beanClass, properties);
449         return this;
450      }
451
452      @Override /* Overridden from Builder */
453      public Builder beanPropertiesExcludes(String beanClassName, String properties) {
454         super.beanPropertiesExcludes(beanClassName, properties);
455         return this;
456      }
457
458      @Override /* Overridden from Builder */
459      public Builder beanPropertiesReadOnly(Map<String,Object> values) {
460         super.beanPropertiesReadOnly(values);
461         return this;
462      }
463
464      @Override /* Overridden from Builder */
465      public Builder beanPropertiesReadOnly(Class<?> beanClass, String properties) {
466         super.beanPropertiesReadOnly(beanClass, properties);
467         return this;
468      }
469
470      @Override /* Overridden from Builder */
471      public Builder beanPropertiesReadOnly(String beanClassName, String properties) {
472         super.beanPropertiesReadOnly(beanClassName, properties);
473         return this;
474      }
475
476      @Override /* Overridden from Builder */
477      public Builder beanPropertiesWriteOnly(Map<String,Object> values) {
478         super.beanPropertiesWriteOnly(values);
479         return this;
480      }
481
482      @Override /* Overridden from Builder */
483      public Builder beanPropertiesWriteOnly(Class<?> beanClass, String properties) {
484         super.beanPropertiesWriteOnly(beanClass, properties);
485         return this;
486      }
487
488      @Override /* Overridden from Builder */
489      public Builder beanPropertiesWriteOnly(String beanClassName, String properties) {
490         super.beanPropertiesWriteOnly(beanClassName, properties);
491         return this;
492      }
493
494      @Override /* Overridden from Builder */
495      public Builder beansRequireDefaultConstructor() {
496         super.beansRequireDefaultConstructor();
497         return this;
498      }
499
500      @Override /* Overridden from Builder */
501      public Builder beansRequireSerializable() {
502         super.beansRequireSerializable();
503         return this;
504      }
505
506      @Override /* Overridden from Builder */
507      public Builder beansRequireSettersForGetters() {
508         super.beansRequireSettersForGetters();
509         return this;
510      }
511
512      @Override /* Overridden from Builder */
513      public Builder dictionaryOn(Class<?> on, java.lang.Class<?>...values) {
514         super.dictionaryOn(on, values);
515         return this;
516      }
517
518      @Override /* Overridden from Builder */
519      public Builder disableBeansRequireSomeProperties() {
520         super.disableBeansRequireSomeProperties();
521         return this;
522      }
523
524      @Override /* Overridden from Builder */
525      public Builder disableIgnoreMissingSetters() {
526         super.disableIgnoreMissingSetters();
527         return this;
528      }
529
530      @Override /* Overridden from Builder */
531      public Builder disableIgnoreTransientFields() {
532         super.disableIgnoreTransientFields();
533         return this;
534      }
535
536      @Override /* Overridden from Builder */
537      public Builder disableIgnoreUnknownNullBeanProperties() {
538         super.disableIgnoreUnknownNullBeanProperties();
539         return this;
540      }
541
542      @Override /* Overridden from Builder */
543      public Builder disableInterfaceProxies() {
544         super.disableInterfaceProxies();
545         return this;
546      }
547
548      @Override /* Overridden from Builder */
549      public <T> Builder example(Class<T> pojoClass, T o) {
550         super.example(pojoClass, o);
551         return this;
552      }
553
554      @Override /* Overridden from Builder */
555      public <T> Builder example(Class<T> pojoClass, String json) {
556         super.example(pojoClass, json);
557         return this;
558      }
559
560      @Override /* Overridden from Builder */
561      public Builder findFluentSetters() {
562         super.findFluentSetters();
563         return this;
564      }
565
566      @Override /* Overridden from Builder */
567      public Builder findFluentSetters(Class<?> on) {
568         super.findFluentSetters(on);
569         return this;
570      }
571
572      @Override /* Overridden from Builder */
573      public Builder ignoreInvocationExceptionsOnGetters() {
574         super.ignoreInvocationExceptionsOnGetters();
575         return this;
576      }
577
578      @Override /* Overridden from Builder */
579      public Builder ignoreInvocationExceptionsOnSetters() {
580         super.ignoreInvocationExceptionsOnSetters();
581         return this;
582      }
583
584      @Override /* Overridden from Builder */
585      public Builder ignoreUnknownBeanProperties() {
586         super.ignoreUnknownBeanProperties();
587         return this;
588      }
589
590      @Override /* Overridden from Builder */
591      public Builder ignoreUnknownEnumValues() {
592         super.ignoreUnknownEnumValues();
593         return this;
594      }
595
596      @Override /* Overridden from Builder */
597      public Builder implClass(Class<?> interfaceClass, Class<?> implClass) {
598         super.implClass(interfaceClass, implClass);
599         return this;
600      }
601
602      @Override /* Overridden from Builder */
603      public Builder implClasses(Map<Class<?>,Class<?>> values) {
604         super.implClasses(values);
605         return this;
606      }
607
608      @Override /* Overridden from Builder */
609      public Builder interfaceClass(Class<?> on, Class<?> value) {
610         super.interfaceClass(on, value);
611         return this;
612      }
613
614      @Override /* Overridden from Builder */
615      public Builder interfaces(java.lang.Class<?>...value) {
616         super.interfaces(value);
617         return this;
618      }
619
620      @Override /* Overridden from Builder */
621      public Builder locale(Locale value) {
622         super.locale(value);
623         return this;
624      }
625
626      @Override /* Overridden from Builder */
627      public Builder mediaType(MediaType value) {
628         super.mediaType(value);
629         return this;
630      }
631
632      @Override /* Overridden from Builder */
633      public Builder notBeanClasses(java.lang.Class<?>...values) {
634         super.notBeanClasses(values);
635         return this;
636      }
637
638      @Override /* Overridden from Builder */
639      public Builder notBeanPackages(String...values) {
640         super.notBeanPackages(values);
641         return this;
642      }
643
644      @Override /* Overridden from Builder */
645      public Builder propertyNamer(Class<? extends org.apache.juneau.PropertyNamer> value) {
646         super.propertyNamer(value);
647         return this;
648      }
649
650      @Override /* Overridden from Builder */
651      public Builder propertyNamer(Class<?> on, Class<? extends org.apache.juneau.PropertyNamer> value) {
652         super.propertyNamer(on, value);
653         return this;
654      }
655
656      @Override /* Overridden from Builder */
657      public Builder sortProperties() {
658         super.sortProperties();
659         return this;
660      }
661
662      @Override /* Overridden from Builder */
663      public Builder sortProperties(java.lang.Class<?>...on) {
664         super.sortProperties(on);
665         return this;
666      }
667
668      @Override /* Overridden from Builder */
669      public Builder stopClass(Class<?> on, Class<?> value) {
670         super.stopClass(on, value);
671         return this;
672      }
673
674      @Override /* Overridden from Builder */
675      public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction) {
676         super.swap(normalClass, swappedClass, swapFunction);
677         return this;
678      }
679
680      @Override /* Overridden from Builder */
681      public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction, ThrowingFunction<S,T> unswapFunction) {
682         super.swap(normalClass, swappedClass, swapFunction, unswapFunction);
683         return this;
684      }
685
686      @Override /* Overridden from Builder */
687      public Builder swaps(Object...values) {
688         super.swaps(values);
689         return this;
690      }
691
692      @Override /* Overridden from Builder */
693      public Builder swaps(Class<?>...values) {
694         super.swaps(values);
695         return this;
696      }
697
698      @Override /* Overridden from Builder */
699      public Builder timeZone(TimeZone value) {
700         super.timeZone(value);
701         return this;
702      }
703
704      @Override /* Overridden from Builder */
705      public Builder typeName(Class<?> on, String value) {
706         super.typeName(on, value);
707         return this;
708      }
709
710      @Override /* Overridden from Builder */
711      public Builder typePropertyName(String value) {
712         super.typePropertyName(value);
713         return this;
714      }
715
716      @Override /* Overridden from Builder */
717      public Builder typePropertyName(Class<?> on, String value) {
718         super.typePropertyName(on, value);
719         return this;
720      }
721
722      @Override /* Overridden from Builder */
723      public Builder useEnumNames() {
724         super.useEnumNames();
725         return this;
726      }
727
728      @Override /* Overridden from Builder */
729      public Builder useJavaBeanIntrospector() {
730         super.useJavaBeanIntrospector();
731         return this;
732      }
733
734      @Override /* Overridden from Builder */
735      public Builder detectRecursions() {
736         super.detectRecursions();
737         return this;
738      }
739
740      @Override /* Overridden from Builder */
741      public Builder detectRecursions(boolean value) {
742         super.detectRecursions(value);
743         return this;
744      }
745
746      @Override /* Overridden from Builder */
747      public Builder ignoreRecursions() {
748         super.ignoreRecursions();
749         return this;
750      }
751
752      @Override /* Overridden from Builder */
753      public Builder ignoreRecursions(boolean value) {
754         super.ignoreRecursions(value);
755         return this;
756      }
757
758      @Override /* Overridden from Builder */
759      public Builder initialDepth(int value) {
760         super.initialDepth(value);
761         return this;
762      }
763
764      @Override /* Overridden from Builder */
765      public Builder maxDepth(int value) {
766         super.maxDepth(value);
767         return this;
768      }
769
770      @Override /* Overridden from Builder */
771      public Builder accept(String value) {
772         super.accept(value);
773         return this;
774      }
775
776      @Override /* Overridden from Builder */
777      public Builder addBeanTypes() {
778         super.addBeanTypes();
779         return this;
780      }
781
782      @Override /* Overridden from Builder */
783      public Builder addBeanTypes(boolean value) {
784         super.addBeanTypes(value);
785         return this;
786      }
787
788      @Override /* Overridden from Builder */
789      public Builder addRootType() {
790         super.addRootType();
791         return this;
792      }
793
794      @Override /* Overridden from Builder */
795      public Builder addRootType(boolean value) {
796         super.addRootType(value);
797         return this;
798      }
799
800      @Override /* Overridden from Builder */
801      public Builder keepNullProperties() {
802         super.keepNullProperties();
803         return this;
804      }
805
806      @Override /* Overridden from Builder */
807      public Builder keepNullProperties(boolean value) {
808         super.keepNullProperties(value);
809         return this;
810      }
811
812      @Override /* Overridden from Builder */
813      public Builder listener(Class<? extends org.apache.juneau.serializer.SerializerListener> value) {
814         super.listener(value);
815         return this;
816      }
817
818      @Override /* Overridden from Builder */
819      public Builder produces(String value) {
820         super.produces(value);
821         return this;
822      }
823
824      @Override /* Overridden from Builder */
825      public Builder sortCollections() {
826         super.sortCollections();
827         return this;
828      }
829
830      @Override /* Overridden from Builder */
831      public Builder sortCollections(boolean value) {
832         super.sortCollections(value);
833         return this;
834      }
835
836      @Override /* Overridden from Builder */
837      public Builder sortMaps() {
838         super.sortMaps();
839         return this;
840      }
841
842      @Override /* Overridden from Builder */
843      public Builder sortMaps(boolean value) {
844         super.sortMaps(value);
845         return this;
846      }
847
848      @Override /* Overridden from Builder */
849      public Builder trimEmptyCollections() {
850         super.trimEmptyCollections();
851         return this;
852      }
853
854      @Override /* Overridden from Builder */
855      public Builder trimEmptyCollections(boolean value) {
856         super.trimEmptyCollections(value);
857         return this;
858      }
859
860      @Override /* Overridden from Builder */
861      public Builder trimEmptyMaps() {
862         super.trimEmptyMaps();
863         return this;
864      }
865
866      @Override /* Overridden from Builder */
867      public Builder trimEmptyMaps(boolean value) {
868         super.trimEmptyMaps(value);
869         return this;
870      }
871
872      @Override /* Overridden from Builder */
873      public Builder trimStrings() {
874         super.trimStrings();
875         return this;
876      }
877
878      @Override /* Overridden from Builder */
879      public Builder trimStrings(boolean value) {
880         super.trimStrings(value);
881         return this;
882      }
883
884      @Override /* Overridden from Builder */
885      public Builder uriContext(UriContext value) {
886         super.uriContext(value);
887         return this;
888      }
889
890      @Override /* Overridden from Builder */
891      public Builder uriRelativity(UriRelativity value) {
892         super.uriRelativity(value);
893         return this;
894      }
895
896      @Override /* Overridden from Builder */
897      public Builder uriResolution(UriResolution value) {
898         super.uriResolution(value);
899         return this;
900      }
901
902      @Override /* Overridden from Builder */
903      public Builder fileCharset(Charset value) {
904         super.fileCharset(value);
905         return this;
906      }
907
908      @Override /* Overridden from Builder */
909      public Builder maxIndent(int value) {
910         super.maxIndent(value);
911         return this;
912      }
913
914      @Override /* Overridden from Builder */
915      public Builder quoteChar(char value) {
916         super.quoteChar(value);
917         return this;
918      }
919
920      @Override /* Overridden from Builder */
921      public Builder quoteCharOverride(char value) {
922         super.quoteCharOverride(value);
923         return this;
924      }
925
926      @Override /* Overridden from Builder */
927      public Builder sq() {
928         super.sq();
929         return this;
930      }
931
932      @Override /* Overridden from Builder */
933      public Builder streamCharset(Charset value) {
934         super.streamCharset(value);
935         return this;
936      }
937
938      @Override /* Overridden from Builder */
939      public Builder useWhitespace() {
940         super.useWhitespace();
941         return this;
942      }
943
944      @Override /* Overridden from Builder */
945      public Builder useWhitespace(boolean value) {
946         super.useWhitespace(value);
947         return this;
948      }
949
950      @Override /* Overridden from Builder */
951      public Builder ws() {
952         super.ws();
953         return this;
954      }
955
956      @Override /* Overridden from Builder */
957      public Builder addBeanTypesJson() {
958         super.addBeanTypesJson();
959         return this;
960      }
961
962      @Override /* Overridden from Builder */
963      public Builder addBeanTypesJson(boolean value) {
964         super.addBeanTypesJson(value);
965         return this;
966      }
967
968      @Override /* Overridden from Builder */
969      public Builder escapeSolidus() {
970         super.escapeSolidus();
971         return this;
972      }
973
974      @Override /* Overridden from Builder */
975      public Builder escapeSolidus(boolean value) {
976         super.escapeSolidus(value);
977         return this;
978      }
979
980      @Override /* Overridden from Builder */
981      public Builder simpleAttrs() {
982         super.simpleAttrs();
983         return this;
984      }
985
986      @Override /* Overridden from Builder */
987      public Builder simpleAttrs(boolean value) {
988         super.simpleAttrs(value);
989         return this;
990      }
991
992      @Override /* Overridden from Builder */
993      public Builder json5() {
994         super.json5();
995         return this;
996      }
997   }
998
999   //-------------------------------------------------------------------------------------------------------------------
1000   // Instance
1001   //-------------------------------------------------------------------------------------------------------------------
1002
1003   final JsonSchemaGenerator generator;
1004
1005   private final Map<ClassMeta<?>,JsonSchemaClassMeta> jsonSchemaClassMetas = new ConcurrentHashMap<>();
1006   private final Map<BeanPropertyMeta,JsonSchemaBeanPropertyMeta> jsonSchemaBeanPropertyMetas = new ConcurrentHashMap<>();
1007
1008   /**
1009    * Constructor.
1010    *
1011    * @param builder The builder for this object.
1012    */
1013   public JsonSchemaSerializer(Builder builder) {
1014      super(builder.detectRecursions().ignoreRecursions());
1015
1016      generator = builder.generatorBuilder.build();
1017   }
1018
1019   @Override /* Context */
1020   public Builder copy() {
1021      return new Builder(this);
1022   }
1023
1024   @Override /* Context */
1025   public JsonSchemaSerializerSession.Builder createSession() {
1026      return JsonSchemaSerializerSession.create(this);
1027   }
1028
1029   @Override /* Context */
1030   public JsonSchemaSerializerSession getSession() {
1031      return createSession().build();
1032   }
1033
1034   JsonSchemaGenerator getGenerator() {
1035      return generator;
1036   }
1037
1038   //-----------------------------------------------------------------------------------------------------------------
1039   // Extended metadata
1040   //-----------------------------------------------------------------------------------------------------------------
1041
1042   @Override /* JsonSchemaMetaProvider */
1043   public JsonSchemaClassMeta getJsonSchemaClassMeta(ClassMeta<?> cm) {
1044      JsonSchemaClassMeta m = jsonSchemaClassMetas.get(cm);
1045      if (m == null) {
1046         m = new JsonSchemaClassMeta(cm, this);
1047         jsonSchemaClassMetas.put(cm, m);
1048      }
1049      return m;
1050   }
1051
1052   @Override /* JsonSchemaMetaProvider */
1053   public JsonSchemaBeanPropertyMeta getJsonSchemaBeanPropertyMeta(BeanPropertyMeta bpm) {
1054      JsonSchemaBeanPropertyMeta m = jsonSchemaBeanPropertyMetas.get(bpm);
1055      if (m == null) {
1056         m = new JsonSchemaBeanPropertyMeta(bpm.getDelegateFor(), this);
1057         jsonSchemaBeanPropertyMetas.put(bpm, m);
1058      }
1059      return m;
1060   }
1061
1062   //-----------------------------------------------------------------------------------------------------------------
1063   // Other methods
1064   //-----------------------------------------------------------------------------------------------------------------
1065
1066   @Override /* Context */
1067   protected JsonMap properties() {
1068      return filteredMap("generator", generator);
1069   }
1070}