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