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.dto.jsonschema;
014
015import static org.apache.juneau.internal.StringUtils.*;
016
017import java.net.*;
018import java.net.URI;
019import java.util.*;
020
021import org.apache.juneau.*;
022import org.apache.juneau.annotation.*;
023import org.apache.juneau.json.*;
024import org.apache.juneau.parser.*;
025import org.apache.juneau.serializer.*;
026import org.apache.juneau.transform.*;
027
028/**
029 * Represents a top-level schema object bean in the JSON-Schema core specification.
030 *
031 * <ul class='seealso'>
032 *    <li class='jp'>{@doc package-summary.html#TOC org.apache.juneau.dto.jsonschema}
033 * </ul>
034 */
035@Bean(typeName="schema",
036   bpi="id,$schema,$ref, title,description,type,definitions,properties,"
037      + "patternProperties,dependencies,items,multipleOf,maximum,exclusiveMaximum,"
038      + "minimum,exclusiveMinimum,maxLength,minLength,pattern,additionalItems,"
039      + "maxItems,minItems,uniqueItems,maxProperties,minProperties,required,"
040      + "additionalProperties,enum,allOf,anyOf,oneOf,not"
041)
042public class JsonSchema {
043   private String name;                                   // Property name.  Not serialized.
044   private URI id;
045   private URI schemaVersion;
046   private String title;
047   private String description;
048   private JsonType typeJsonType;                         // JsonType representation of type
049   private JsonTypeArray typeJsonTypeArray;               // JsonTypeArray representation of type
050   private Map<String,JsonSchema> definitions;
051   private Map<String,JsonSchema> properties;
052   private Map<String,JsonSchema> patternProperties;
053   private Map<String,JsonSchema> dependencies;
054   private JsonSchema itemsSchema;                            // JsonSchema representation of items
055   private JsonSchemaArray itemsSchemaArray;                  // JsonSchemaArray representation of items
056   private Number multipleOf;
057   private Number maximum;
058   private Boolean exclusiveMaximum;
059   private Number minimum;
060   private Boolean exclusiveMinimum;
061   private Integer maxLength;
062   private Integer minLength;
063   private String pattern;
064   private Boolean additionalItemsBoolean;                // Boolean representation of additionalItems
065   private JsonSchemaArray additionalItemsSchemaArray;        // JsonSchemaArray representation of additionalItems
066   private Integer maxItems;
067   private Integer minItems;
068   private Boolean uniqueItems;
069   private Integer maxProperties;
070   private Integer minProperties;
071   private List<String> required;
072   private Boolean additionalPropertiesBoolean;           // Boolean representation of additionalProperties
073   private JsonSchema additionalPropertiesSchema;             // JsonSchema representation of additionalProperties
074   private List<String> _enum;
075   private List<JsonSchema> allOf;
076   private List<JsonSchema> anyOf;
077   private List<JsonSchema> oneOf;
078   private JsonSchema not;
079   private URI ref;
080   private JsonSchemaMap schemaMap;
081   private JsonSchema master = this;
082
083   /**
084    * Default constructor.
085    */
086   public JsonSchema() {}
087
088
089   //-----------------------------------------------------------------------------------------------------------------
090   // Bean properties
091   //-----------------------------------------------------------------------------------------------------------------
092
093   /**
094    * Bean property getter:  <property>name</property>.
095    *
096    * @return The value of the <property>name</property> property on this bean, or <jk>null</jk> if it is not set.
097    */
098   @BeanIgnore
099   public String getName() {
100      return name;
101   }
102
103   /**
104    * Bean property setter:  <property>name</property>.
105    *
106    * @param name The new value for the <property>name</property> property on this bean.
107    * @return This object (for method chaining).
108    */
109   @BeanIgnore
110   public JsonSchema setName(String name) {
111      this.name = name;
112      return this;
113   }
114
115   /**
116    * Bean property getter:  <property>id</property>.
117    *
118    * @return The value of the <property>id</property> property on this bean, or <jk>null</jk> if it is not set.
119    */
120   public URI getId() {
121      return id;
122   }
123
124   /**
125    * Bean property setter:  <property>id</property>.
126    *
127    * <p>
128    * The value can be of any of the following types: {@link URI}, {@link URL}, {@link String}.
129    * Strings must be valid URIs.
130    *
131    * <p>
132    * URIs defined by {@link UriResolver} can be used for values.
133    *
134    * @param id The new value for the <property>id</property> property on this bean.
135    * @return This object (for method chaining).
136    */
137   public JsonSchema setId(Object id) {
138      this.id = toURI(id);
139      return this;
140   }
141
142   /**
143    * Bean property getter:  <property>$schema</property>.
144    *
145    * @return The value of the <property>$schema</property> property on this bean, or <jk>null</jk> if it is not set.
146    */
147   @Beanp("$schema")
148   public URI getSchemaVersionUri() {
149      return schemaVersion;
150   }
151
152   /**
153    * Bean property setter:  <property>$schema</property>.
154    *
155    * <p>
156    * The value can be of any of the following types: {@link URI}, {@link URL}, {@link String}.
157    * Strings must be valid URIs.
158    *
159    * <p>
160    * URIs defined by {@link UriResolver} can be used for values.
161    *
162    * @param schemaVersion The new value for the <property>schemaVersion</property> property on this bean.
163    * @return This object (for method chaining).
164    */
165   @Beanp("$schema")
166   public JsonSchema setSchemaVersionUri(Object schemaVersion) {
167      this.schemaVersion = toURI(schemaVersion);
168      return this;
169   }
170
171   /**
172    * Bean property getter:  <property>title</property>.
173    *
174    * @return The value of the <property>title</property> property, or <jk>null</jk> if it is not set.
175    */
176   public String getTitle() {
177      return title;
178   }
179
180   /**
181    * Bean property setter:  <property>title</property>.
182    *
183    * @param title The new value for the <property>title</property> property on this bean.
184    * @return This object (for method chaining).
185    */
186   public JsonSchema setTitle(String title) {
187      this.title = title;
188      return this;
189   }
190
191   /**
192    * Bean property getter:  <property>description</property>.
193    *
194    * @return The value of the <property>description</property> property, or <jk>null</jk> if it is not set.
195    */
196   public String getDescription() {
197      return description;
198   }
199
200   /**
201    * Bean property setter:  <property>description</property>.
202    *
203    * @param description The new value for the <property>description</property> property on this bean.
204    * @return This object (for method chaining).
205    */
206   public JsonSchema setDescription(String description) {
207      this.description = description;
208      return this;
209   }
210
211   /**
212    * Bean property getter:  <property>type</property>.
213    *
214    * @return
215    *    The value of the <property>type</property> property on this bean, or <jk>null</jk> if it is not set.
216    *    Can be either a {@link JsonType} or {@link JsonTypeArray} depending on what value was used to set it.
217    */
218   @Swap(JsonTypeOrJsonTypeArraySwap.class)
219   public Object getType() {
220      if (typeJsonType != null)
221         return typeJsonType;
222      return typeJsonTypeArray;
223   }
224
225   /**
226    * Bean property getter:  <property>type</property>.
227    *
228    * <p>
229    * Convenience method for returning the <property>type</property> property when it is a {@link JsonType} value.
230    *
231    * @return
232    *    The currently set value, or <jk>null</jk> if the property is not set, or is set as a {@link JsonTypeArray}.
233    */
234   @BeanIgnore
235   public JsonType getTypeAsJsonType() {
236      return typeJsonType;
237   }
238
239   /**
240    * Bean property getter:  <property>type</property>.
241    *
242    * <p>
243    * Convenience method for returning the <property>type</property> property when it is a {@link JsonTypeArray} value.
244    *
245    * @return The currently set value, or <jk>null</jk> if the property is not set, or is set as a {@link JsonType}.
246    */
247   @BeanIgnore
248   public JsonTypeArray getTypeAsJsonTypeArray() {
249      return typeJsonTypeArray;
250   }
251
252   /**
253    * Bean property setter:  <property>type</property>.
254    *
255    * @param type
256    *    The new value for the <property>type</property> property on this bean.
257    *    This object must be of type {@link JsonType} or {@link JsonTypeArray}.
258    * @return This object (for method chaining).
259    * @throws BeanRuntimeException If invalid object type passed in.
260    */
261   public JsonSchema setType(Object type) {
262      this.typeJsonType = null;
263      this.typeJsonTypeArray = null;
264      if (type != null) {
265         if (type instanceof JsonType)
266            this.typeJsonType = (JsonType)type;
267         else if (type instanceof JsonTypeArray)
268            this.typeJsonTypeArray = (JsonTypeArray)type;
269         else
270            throw new BeanRuntimeException(JsonSchemaProperty.class,
271               "Invalid attribute type ''{0}'' passed in.  Must be one of the following:  SimpleType, SimpleTypeArray",
272               type.getClass().getName());
273      }
274      return this;
275   }
276
277   /**
278    * Bean property appender:  <property>type</property>.
279    *
280    * @param types The list of items to append to the <property>type</property> property on this bean.
281    * @return This object (for method chaining).
282    */
283   public JsonSchema addTypes(JsonType...types) {
284      if (this.typeJsonTypeArray == null)
285         this.typeJsonTypeArray = new JsonTypeArray();
286      this.typeJsonTypeArray.addAll(types);
287      return this;
288   }
289
290   /**
291    * Used during parsing to convert the <property>type</property> property to the correct class type.
292    *
293    * <ul class='spaced-list'>
294    *    <li>
295    *       If parsing a JSON-array, converts to a {@link JsonTypeArray}.
296    *    <li>
297    *       If parsing a JSON-object, converts to a {@link JsonType}.
298    * </ul>
299    *
300    * <p>
301    * Serialization method is a no-op.
302    */
303   public static class JsonTypeOrJsonTypeArraySwap extends PojoSwap<Object,Object> {
304
305      @Override /* PojoSwap */
306      public Object swap(BeanSession session, Object o) throws SerializeException {
307         return o;
308      }
309
310      @Override /* PojoSwap */
311      public Object unswap(BeanSession session, Object o, ClassMeta<?> hint) throws ParseException {
312         ClassMeta<?> cm = (
313            o instanceof Collection
314            ? session.getClassMeta(JsonTypeArray.class)
315            : session.getClassMeta(JsonType.class)
316         );
317         return session.convertToType(o, cm);
318      }
319   }
320
321   /**
322    * Bean property getter:  <property>definitions</property>.
323    *
324    * @return
325    *    The value of the <property>definitions</property> property on this bean, or <jk>null</jk> if it is not set.
326    */
327   public Map<String,JsonSchema> getDefinitions() {
328      return definitions;
329   }
330
331   /**
332    * Bean property setter:  <property>definitions</property>.
333    *
334    * @param definitions The new value for the <property>definitions</property> property on this bean.
335    * @return This object (for method chaining).
336    */
337   public JsonSchema setDefinitions(Map<String,JsonSchema> definitions) {
338      this.definitions = definitions;
339      if (definitions != null)
340         setMasterOn(definitions.values());
341      return this;
342   }
343
344   /**
345    * Bean property appender:  <property>definitions</property>.
346    *
347    * @param name The key in the definitions map entry.
348    * @param definition The value in the definitions map entry.
349    * @return This object (for method chaining).
350    */
351   public JsonSchema addDefinition(String name, JsonSchema definition) {
352      if (this.definitions == null)
353         this.definitions = new LinkedHashMap<>();
354      this.definitions.put(name, definition);
355      setMasterOn(definition);
356      return this;
357   }
358
359   /**
360    * Bean property getter:  <property>properties</property>.
361    *
362    * @return The value of the <property>properties</property> property on this bean, or <jk>null</jk> if it is not set.
363    */
364   public Map<String,JsonSchema> getProperties() {
365      return properties;
366   }
367
368   /**
369    * Returns the property with the specified name.
370    *
371    * <p>
372    * This is equivalent to calling <property>getProperty(name, <jk>false</jk>)</property>.
373    *
374    * @param name The property name.
375    * @return The property with the specified name, or <jk>null</jk> if no property is specified.
376    */
377   public JsonSchema getProperty(String name) {
378      return getProperty(name, false);
379   }
380
381   /**
382    * Returns the property with the specified name.
383    *
384    * <p>
385    * If <property>resolve</property> is <jk>true</jk>, the property object will automatically be  resolved by calling
386    * {@link #resolve()}.
387    * Therefore, <property>getProperty(name, <jk>true</jk>)</property> is equivalent to calling
388    * <property>getProperty(name).resolve()</property>, except it's safe from a potential
389    * <property>NullPointerException</property>.
390    *
391    * @param name The property name.
392    * @param resolve If <jk>true</jk>, calls {@link #resolve()} on object before returning.
393    * @return The property with the specified name, or <jk>null</jk> if no property is specified.
394    */
395   public JsonSchema getProperty(String name, boolean resolve) {
396      if (properties == null)
397         return null;
398      JsonSchema s = properties.get(name);
399      if (s == null)
400         return null;
401      if (resolve)
402         s = s.resolve();
403      return s;
404   }
405
406   /**
407    * Bean property setter:  <property>properties</property>.
408    *
409    * @param properties The new value for the <property>properties</property> property on this bean.
410    * @return This object (for method chaining).
411    */
412   public JsonSchema setProperties(Map<String,JsonSchema> properties) {
413      this.properties = properties;
414      if (properties != null)
415         for (Map.Entry<String,JsonSchema> e : properties.entrySet()) {
416            JsonSchema value = e.getValue();
417            setMasterOn(value);
418            value.setName(e.getKey());
419         }
420      return this;
421   }
422
423   /**
424    * Bean property appender:  <property>properties</property>.
425    *
426    * <p>
427    * Properties must have their <property>name</property> property set on them when using this method.
428    *
429    * @param properties The list of items to append to the <property>properties</property> property on this bean.
430    * @return This object (for method chaining).
431    * @throws BeanRuntimeException If property is found without a set <property>name</property> property.
432    */
433   public JsonSchema addProperties(JsonSchema...properties) {
434      if (this.properties == null)
435         this.properties = new LinkedHashMap<>();
436      for (JsonSchema p : properties) {
437         if (p.getName() == null)
438            throw new BeanRuntimeException(JsonSchema.class,
439               "Invalid property passed to JsonSchema.addProperties().  Property name was null.");
440         setMasterOn(p);
441         this.properties.put(p.getName(), p);
442      }
443      return this;
444   }
445
446   /**
447    * Bean property getter:  <property>patternProperties</property>.
448    *
449    * @return
450    *    The value of the <property>patternProperties</property> property on this bean, or <jk>null</jk> if it is
451    *    not set.
452    */
453   public Map<String,JsonSchema> getPatternProperties() {
454      return patternProperties;
455   }
456
457   /**
458    * Bean property setter:  <property>patternProperties</property>.
459    *
460    * @param patternProperties The new value for the <property>patternProperties</property> property on this bean.
461    * @return This object (for method chaining).
462    */
463   public JsonSchema setPatternProperties(Map<String,JsonSchema> patternProperties) {
464      this.patternProperties = patternProperties;
465      if (patternProperties != null)
466         for (Map.Entry<String,JsonSchema> e : patternProperties.entrySet()) {
467            JsonSchema s = e.getValue();
468            setMasterOn(s);
469            s.setName(e.getKey());
470         }
471      return this;
472   }
473
474   /**
475    * Bean property appender:  <property>patternProperties</property>.
476    *
477    * <p>
478    * Properties must have their <property>name</property> property set to the pattern string when using this method.
479    *
480    * @param properties The list of items to append to the <property>patternProperties</property> property on this bean.
481    * @return This object (for method chaining).
482    * @throws BeanRuntimeException If property is found without a set <property>name</property> property.
483    */
484   public JsonSchema addPatternProperties(JsonSchemaProperty...properties) {
485      if (this.patternProperties == null)
486         this.patternProperties = new LinkedHashMap<>();
487      for (JsonSchema p : properties) {
488         if (p.getName() == null)
489            throw new BeanRuntimeException(JsonSchema.class,
490               "Invalid property passed to JsonSchema.addProperties().  Property name was null.");
491         setMasterOn(p);
492         this.patternProperties.put(p.getName(), p);
493      }
494      return this;
495   }
496
497   /**
498    * Bean property getter:  <property>dependencies</property>.
499    *
500    * @return
501    *    The value of the <property>dependencies</property> property on this bean, or <jk>null</jk> if it is not set.
502    */
503   public Map<String,JsonSchema> getDependencies() {
504      return dependencies;
505   }
506
507   /**
508    * Bean property setter:  <property>dependencies</property>.
509    *
510    * @param dependencies The new value for the <property>dependencies</property> property on this bean.
511    * @return This object (for method chaining).
512    */
513   public JsonSchema setDependencies(Map<String,JsonSchema> dependencies) {
514      this.dependencies = dependencies;
515      if (dependencies != null)
516         setMasterOn(dependencies.values());
517      return this;
518   }
519
520   /**
521    * Bean property appender:  <property>dependencies</property>.
522    *
523    * @param name The key of the entry in the dependencies map.
524    * @param dependency The value of the entry in the dependencies map.
525    * @return This object (for method chaining).
526    */
527   public JsonSchema addDependency(String name, JsonSchema dependency) {
528      if (this.dependencies == null)
529         this.dependencies = new LinkedHashMap<>();
530      this.dependencies.put(name, dependency);
531      setMasterOn(dependency);
532      return this;
533   }
534
535   /**
536    * Bean property getter:  <property>items</property>.
537    *
538    * @return
539    *    The value of the <property>items</property> property on this bean, or <jk>null</jk> if it is not set.
540    *    Can be either a {@link JsonSchema} or {@link JsonSchemaArray} depending on what value was used to set it.
541    */
542   @Swap(JsonSchemaOrSchemaArraySwap.class)
543   public Object getItems() {
544      if (itemsSchema != null)
545         return itemsSchema;
546      return itemsSchemaArray;
547   }
548
549   /**
550    * Bean property getter:  <property>items</property>.
551    *
552    * <p>
553    * Convenience method for returning the <property>items</property> property when it is a {@link JsonSchema} value.
554    *
555    * @return The currently set value, or <jk>null</jk> if the property is not set, or is set as a {@link JsonSchemaArray}.
556    */
557   @BeanIgnore
558   public JsonSchema getItemsAsSchema() {
559      return itemsSchema;
560   }
561
562   /**
563    * Bean property getter:  <property>items</property>.
564    *
565    * <p>
566    * Convenience method for returning the <property>items</property> property when it is a {@link JsonSchemaArray} value.
567    *
568    * @return The currently set value, or <jk>null</jk> if the property is not set, or is set as a {@link JsonSchema}.
569    */
570   @BeanIgnore
571   public JsonSchemaArray getItemsAsSchemaArray() {
572      return itemsSchemaArray;
573   }
574
575   /**
576    * Used during parsing to convert the <property>items</property> property to the correct class type.
577    *
578    * <ul class='spaced-list'>
579    *    <li>
580    *       If parsing a JSON-array, converts to a {@link JsonSchemaArray}.
581    *    <li>
582    *       If parsing a JSON-object, converts to a {@link JsonSchema}.
583    * </ul>
584    *
585    * <p>
586    * Serialization method is a no-op.
587    */
588   public static class JsonSchemaOrSchemaArraySwap extends PojoSwap<Object,Object> {
589
590      @Override /* PojoSwap */
591      public Object swap(BeanSession session, Object o) throws SerializeException {
592         return o;
593      }
594
595      @Override /* PojoSwap */
596      public Object unswap(BeanSession session, Object o, ClassMeta<?> hint) throws ParseException {
597         ClassMeta<?> cm = (
598            o instanceof Collection
599            ? session.getClassMeta(JsonSchemaArray.class)
600            : session.getClassMeta(JsonSchema.class)
601         );
602         return session.convertToType(o, cm);
603      }
604   }
605
606   /**
607    * Bean property setter:  <property>items</property>.
608    *
609    * @param
610    *    items The new value for the <property>items</property> property on this bean.
611    *    This object must be of type {@link JsonSchema} or {@link JsonSchemaArray}.
612    * @return This object (for method chaining).
613    * @throws BeanRuntimeException If invalid object type passed in.
614    */
615   public JsonSchema setItems(Object items) {
616      this.itemsSchema = null;
617      this.itemsSchemaArray = null;
618      if (items != null) {
619         if (items instanceof JsonSchema) {
620            this.itemsSchema = (JsonSchema)items;
621            setMasterOn(this.itemsSchema);
622         } else if (items instanceof JsonSchemaArray) {
623            this.itemsSchemaArray = (JsonSchemaArray)items;
624            setMasterOn(this.itemsSchemaArray);
625         } else
626            throw new BeanRuntimeException(JsonSchemaProperty.class,
627               "Invalid attribute type ''{0}'' passed in.  Must be one of the following:  JsonSchema, JsonSchemaArray",
628               items.getClass().getName());
629      }
630      return this;
631   }
632
633   /**
634    * Bean property appender:  <property>items</property>.
635    *
636    * @param items The list of items to append to the <property>items</property> property on this bean.
637    * @return This object (for method chaining).
638    */
639   public JsonSchema addItems(JsonSchema...items) {
640      if (this.itemsSchemaArray == null)
641         this.itemsSchemaArray = new JsonSchemaArray();
642      this.itemsSchemaArray.addAll(items);
643      setMasterOn(items);
644      return this;
645   }
646
647   /**
648    * Bean property getter:  <property>multipleOf</property>.
649    *
650    * @return The value of the <property>multipleOf</property> property on this bean, or <jk>null</jk> if it is not set.
651    */
652   public Number getMultipleOf() {
653      return multipleOf;
654   }
655
656   /**
657    * Bean property setter:  <property>multipleOf</property>.
658    *
659    * @param multipleOf The new value for the <property>multipleOf</property> property on this bean.
660    * @return This object (for method chaining).
661    */
662   public JsonSchema setMultipleOf(Number multipleOf) {
663      this.multipleOf = multipleOf;
664      return this;
665   }
666
667   /**
668    * Bean property getter:  <property>maximum</property>.
669    *
670    * @return The value of the <property>maximum</property> property on this bean, or <jk>null</jk> if it is not set.
671    */
672   public Number getMaximum() {
673      return maximum;
674   }
675
676   /**
677    * Bean property setter:  <property>maximum</property>.
678    *
679    * @param maximum The new value for the <property>maximum</property> property on this bean.
680    * @return This object (for method chaining).
681    */
682   public JsonSchema setMaximum(Number maximum) {
683      this.maximum = maximum;
684      return this;
685   }
686
687   /**
688    * Bean property getter:  <property>exclusiveMaximum</property>.
689    *
690    * @return
691    *    The value of the <property>exclusiveMaximum</property> property on this bean, or <jk>null</jk> if it is
692    *    not set.
693    */
694   public Boolean isExclusiveMaximum() {
695      return exclusiveMaximum;
696   }
697
698   /**
699    * Bean property setter:  <property>exclusiveMaximum</property>.
700    *
701    * @param exclusiveMaximum The new value for the <property>exclusiveMaximum</property> property on this bean.
702    * @return This object (for method chaining).
703    */
704   public JsonSchema setExclusiveMaximum(Boolean exclusiveMaximum) {
705      this.exclusiveMaximum = exclusiveMaximum;
706      return this;
707   }
708
709   /**
710    * Bean property getter:  <property>minimum</property>.
711    *
712    * @return The value of the <property>minimum</property> property on this bean, or <jk>null</jk> if it is not set.
713    */
714   public Number getMinimum() {
715      return minimum;
716   }
717
718   /**
719    * Bean property setter:  <property>minimum</property>.
720    *
721    * @param minimum The new value for the <property>minimum</property> property on this bean.
722    * @return This object (for method chaining).
723    */
724   public JsonSchema setMinimum(Number minimum) {
725      this.minimum = minimum;
726      return this;
727   }
728
729   /**
730    * Bean property getter:  <property>exclusiveMinimum</property>.
731    *
732    * @return
733    *    The value of the <property>exclusiveMinimum</property> property on this bean, or <jk>null</jk> if it is
734    *    not set.
735    */
736   public Boolean isExclusiveMinimum() {
737      return exclusiveMinimum;
738   }
739
740   /**
741    * Bean property setter:  <property>exclusiveMinimum</property>.
742    *
743    * @param exclusiveMinimum The new value for the <property>exclusiveMinimum</property> property on this bean.
744    * @return This object (for method chaining).
745    */
746   public JsonSchema setExclusiveMinimum(Boolean exclusiveMinimum) {
747      this.exclusiveMinimum = exclusiveMinimum;
748      return this;
749   }
750
751   /**
752    * Bean property getter:  <property>maxLength</property>.
753    *
754    * @return The value of the <property>maxLength</property> property on this bean, or <jk>null</jk> if it is not set.
755    */
756   public Integer getMaxLength() {
757      return maxLength;
758   }
759
760   /**
761    * Bean property setter:  <property>maxLength</property>.
762    *
763    * @param maxLength The new value for the <property>maxLength</property> property on this bean.
764    * @return This object (for method chaining).
765    */
766   public JsonSchema setMaxLength(Integer maxLength) {
767      this.maxLength = maxLength;
768      return this;
769   }
770
771   /**
772    * Bean property getter:  <property>minLength</property>.
773    *
774    * @return The value of the <property>minLength</property> property on this bean, or <jk>null</jk> if it is not set.
775    */
776   public Integer getMinLength() {
777      return minLength;
778   }
779
780   /**
781    * Bean property setter:  <property>minLength</property>.
782    *
783    * @param minLength The new value for the <property>minLength</property> property on this bean.
784    * @return This object (for method chaining).
785    */
786   public JsonSchema setMinLength(Integer minLength) {
787      this.minLength = minLength;
788      return this;
789   }
790
791   /**
792    * Bean property getter:  <property>pattern</property>.
793    *
794    * @return The value of the <property>pattern</property> property on this bean, or <jk>null</jk> if it is not set.
795    */
796   public String getPattern() {
797      return pattern;
798   }
799
800   /**
801    * Bean property setter:  <property>pattern</property>.
802    *
803    * @param pattern The new value for the <property>pattern</property> property on this bean.
804    * @return This object (for method chaining).
805    */
806   public JsonSchema setPattern(String pattern) {
807      this.pattern = pattern;
808      return this;
809   }
810
811   /**
812    * Bean property getter:  <property>additionalItems</property>.
813    *
814    * @return
815    *    The value of the <property>additionalItems</property> property on this bean, or <jk>null</jk> if it is
816    *    not set.
817    *    Can be either a {@link Boolean} or {@link JsonSchemaArray} depending on what value was used to set it.
818    */
819   @Swap(BooleanOrSchemaArraySwap.class)
820   public Object getAdditionalItems() {
821      if (additionalItemsBoolean != null)
822         return additionalItemsBoolean;
823      return additionalItemsSchemaArray;
824   }
825
826   /**
827    * Bean property getter:  <property>additionalItems</property>.
828    *
829    * <p>
830    * Convenience method for returning the <property>additionalItems</property> property when it is a {@link Boolean}
831    * value.
832    *
833    * @return The currently set value, or <jk>null</jk> if the property is not set, or is set as a {@link JsonSchemaArray}.
834    */
835   @BeanIgnore
836   public Boolean getAdditionalItemsAsBoolean() {
837      return additionalItemsBoolean;
838   }
839
840   /**
841    * Bean property getter:  <property>additionalItems</property>.
842    *
843    * <p>
844    * Convenience method for returning the <property>additionalItems</property> property when it is a
845    * {@link JsonSchemaArray} value.
846    *
847    * @return The currently set value, or <jk>null</jk> if the property is not set, or is set as a {@link Boolean}.
848    */
849   @BeanIgnore
850   public List<JsonSchema> getAdditionalItemsAsSchemaArray() {
851      return additionalItemsSchemaArray;
852   }
853
854   /**
855    * Bean property setter:  <property>additionalItems</property>.
856    *
857    * @param additionalItems
858    *    The new value for the <property>additionalItems</property> property on this bean.
859    *    This object must be of type {@link Boolean} or {@link JsonSchemaArray}.
860    * @return This object (for method chaining).
861    * @throws BeanRuntimeException If invalid object type passed in.
862    */
863   public JsonSchema setAdditionalItems(Object additionalItems) {
864      this.additionalItemsBoolean = null;
865      this.additionalItemsSchemaArray = null;
866      if (additionalItems != null) {
867         if (additionalItems instanceof Boolean)
868            this.additionalItemsBoolean = (Boolean)additionalItems;
869         else if (additionalItems instanceof JsonSchemaArray) {
870            this.additionalItemsSchemaArray = (JsonSchemaArray)additionalItems;
871            setMasterOn(this.additionalItemsSchemaArray);
872         } else
873            throw new BeanRuntimeException(JsonSchemaProperty.class,
874               "Invalid attribute type ''{0}'' passed in.  Must be one of the following:  Boolean, JsonSchemaArray",
875               additionalItems.getClass().getName());
876      }
877      return this;
878   }
879
880   /**
881    * Bean property appender:  <property>additionalItems</property>.
882    *
883    * @param additionalItems
884    *    The list of items to append to the <property>additionalItems</property> property on this bean.
885    * @return This object (for method chaining).
886    */
887   public JsonSchema addAdditionalItems(JsonSchema...additionalItems) {
888      if (this.additionalItemsSchemaArray == null)
889         this.additionalItemsSchemaArray = new JsonSchemaArray();
890      this.additionalItemsSchemaArray.addAll(additionalItems);
891      setMasterOn(additionalItems);
892      return this;
893   }
894
895   /**
896    * Used during parsing to convert the <property>additionalItems</property> property to the correct class type.
897    *
898    * <ul class='spaced-list'>
899    *    <li>
900    *       If parsing a JSON-array, converts to a {@link JsonSchemaArray}.
901    *    <li>
902    *       If parsing a JSON-boolean, converts to a {@link Boolean}.
903    * </ul>
904    *
905    * <p>
906    * Serialization method is a no-op.
907    */
908   public static class BooleanOrSchemaArraySwap extends PojoSwap<Object,Object> {
909
910      @Override /* PojoSwap */
911      public Object swap(BeanSession session, Object o) throws SerializeException {
912         return o;
913      }
914
915      @Override /* PojoSwap */
916      public Object unswap(BeanSession session, Object o, ClassMeta<?> hint) throws ParseException {
917         ClassMeta<?> cm = (
918            o instanceof Collection
919            ? session.getClassMeta(JsonSchemaArray.class)
920            : session.getClassMeta(Boolean.class)
921         );
922         return session.convertToType(o, cm);
923      }
924   }
925
926   /**
927    * Bean property getter:  <property>maxItems</property>.
928    *
929    * @return The value of the <property>maxItems</property> property on this bean, or <jk>null</jk> if it is not set.
930    */
931   public Integer getMaxItems() {
932      return maxItems;
933   }
934
935   /**
936    * Bean property setter:  <property>maxItems</property>.
937    *
938    * @param maxItems The new value for the <property>maxItems</property> property on this bean.
939    * @return This object (for method chaining).
940    */
941   public JsonSchema setMaxItems(Integer maxItems) {
942      this.maxItems = maxItems;
943      return this;
944   }
945
946   /**
947    * Bean property getter:  <property>minItems</property>.
948    *
949    * @return The value of the <property>minItems</property> property on this bean, or <jk>null</jk> if it is not set.
950    */
951   public Integer getMinItems() {
952      return minItems;
953   }
954
955   /**
956    * Bean property setter:  <property>minItems</property>.
957    *
958    * @param minItems The new value for the <property>minItems</property> property on this bean.
959    * @return This object (for method chaining).
960    */
961   public JsonSchema setMinItems(Integer minItems) {
962      this.minItems = minItems;
963      return this;
964   }
965
966   /**
967    * Bean property getter:  <property>uniqueItems</property>.
968    *
969    * @return
970    *    The value of the <property>uniqueItems</property> property on this bean, or <jk>null</jk> if it is not set.
971    */
972   public Boolean getUniqueItems() {
973      return uniqueItems;
974   }
975
976   /**
977    * Bean property setter:  <property>uniqueItems</property>.
978    *
979    * @param uniqueItems The new value for the <property>uniqueItems</property> property on this bean.
980    * @return This object (for method chaining).
981    */
982   public JsonSchema setUniqueItems(Boolean uniqueItems) {
983      this.uniqueItems = uniqueItems;
984      return this;
985   }
986
987   /**
988    * Bean property getter:  <property>maxProperties</property>.
989    *
990    * @return
991    *    The value of the <property>maxProperties</property> property on this bean, or <jk>null</jk> if it is not set.
992    */
993   public Integer getMaxProperties() {
994      return maxProperties;
995   }
996
997   /**
998    * Bean property setter:  <property>maxProperties</property>.
999    *
1000    * @param maxProperties The new value for the <property>maxProperties</property> property on this bean.
1001    * @return This object (for method chaining).
1002    */
1003   public JsonSchema setMaxProperties(Integer maxProperties) {
1004      this.maxProperties = maxProperties;
1005      return this;
1006   }
1007
1008   /**
1009    * Bean property getter:  <property>minProperties</property>.
1010    *
1011    * @return
1012    *    The value of the <property>minProperties</property> property on this bean, or <jk>null</jk> if it is not set.
1013    */
1014   public Integer getMinProperties() {
1015      return minProperties;
1016   }
1017
1018   /**
1019    * Bean property setter:  <property>minProperties</property>.
1020    *
1021    * @param minProperties The new value for the <property>minProperties</property> property on this bean.
1022    * @return This object (for method chaining).
1023    */
1024   public JsonSchema setMinProperties(Integer minProperties) {
1025      this.minProperties = minProperties;
1026      return this;
1027   }
1028
1029   /**
1030    * Bean property getter:  <property>required</property>.
1031    *
1032    * @return The value of the <property>required</property> property on this bean, or <jk>null</jk> if it is not set.
1033    */
1034   public List<String> getRequired() {
1035      return required;
1036   }
1037
1038   /**
1039    * Bean property setter:  <property>required</property>.
1040    *
1041    * @param required The new value for the <property>required</property> property on this bean.
1042    * @return This object (for method chaining).
1043    */
1044   public JsonSchema setRequired(List<String> required) {
1045      this.required = required;
1046      return this;
1047   }
1048
1049   /**
1050    * Bean property appender:  <property>required</property>.
1051    *
1052    * @param required The list of items to append to the <property>required</property> property on this bean.
1053    * @return This object (for method chaining).
1054    */
1055   public JsonSchema addRequired(List<String> required) {
1056      if (this.required == null)
1057         this.required = new LinkedList<>();
1058      for (String r : required)
1059         this.required.add(r);
1060      return this;
1061   }
1062
1063   /**
1064    * Bean property appender:  <property>required</property>.
1065    *
1066    * @param required The list of items to append to the <property>required</property> property on this bean.
1067    * @return This object (for method chaining).
1068    */
1069   public JsonSchema addRequired(String...required) {
1070      if (this.required == null)
1071         this.required = new LinkedList<>();
1072      for (String r : required)
1073         this.required.add(r);
1074      return this;
1075   }
1076
1077   /**
1078    * Bean property appender:  <property>required</property>.
1079    *
1080    * @param properties The list of items to append to the <property>required</property> property on this bean.
1081    * @return This object (for method chaining).
1082    */
1083   public JsonSchema addRequired(JsonSchemaProperty...properties) {
1084      if (this.required == null)
1085         this.required = new LinkedList<>();
1086      for (JsonSchemaProperty p : properties)
1087         this.required.add(p.getName());
1088      return this;
1089   }
1090
1091   /**
1092    * Bean property getter:  <property>additionalProperties</property>.
1093    *
1094    * @return
1095    *    The value of the <property>additionalProperties</property> property on this bean, or <jk>null</jk> if it
1096    *    is not set.
1097    *    Can be either a {@link Boolean} or {@link JsonSchemaArray} depending on what value was used to set it.
1098    */
1099   @Swap(BooleanOrSchemaSwap.class)
1100   public Object getAdditionalProperties() {
1101      if (additionalPropertiesBoolean != null)
1102         return additionalItemsBoolean;
1103      return additionalPropertiesSchema;
1104   }
1105
1106   /**
1107    * Bean property getter:  <property>additionalProperties</property>.
1108    *
1109    * <p>
1110    * Convenience method for returning the <property>additionalProperties</property> property when it is a
1111    * {@link Boolean} value.
1112    *
1113    * @return The currently set value, or <jk>null</jk> if the property is not set, or is set as a {@link JsonSchema}.
1114    */
1115   @BeanIgnore
1116   public Boolean getAdditionalPropertiesAsBoolean() {
1117      return additionalPropertiesBoolean;
1118   }
1119
1120   /**
1121    * Bean property getter:  <property>additionalProperties</property>.
1122    *
1123    * <p>
1124    * Convenience method for returning the <property>additionalProperties</property> property when it is a
1125    * {@link JsonSchema} value.
1126    *
1127    * @return The currently set value, or <jk>null</jk> if the property is not set, or is set as a {@link Boolean}.
1128    */
1129   @BeanIgnore
1130   public JsonSchema getAdditionalPropertiesAsSchema() {
1131      return additionalPropertiesSchema;
1132   }
1133
1134   /**
1135    * Bean property setter:  <property>additionalProperties</property>.
1136    *
1137    * @param additionalProperties
1138    *    The new value for the <property>additionalProperties</property> property on this bean.
1139    *    This object must be of type {@link Boolean} or {@link JsonSchema}.
1140    * @return This object (for method chaining).
1141    * @throws BeanRuntimeException If invalid object type passed in.
1142    */
1143   @Beanp(dictionary={JsonSchema.class})
1144   public JsonSchema setAdditionalProperties(Object additionalProperties) {
1145      this.additionalPropertiesBoolean = null;
1146      this.additionalPropertiesSchema = null;
1147      if (additionalProperties != null) {
1148         if (additionalProperties instanceof Boolean)
1149            this.additionalPropertiesBoolean = (Boolean)additionalProperties;
1150         else if (additionalProperties instanceof JsonSchema) {
1151            this.additionalPropertiesSchema = (JsonSchema)additionalProperties;
1152            setMasterOn(this.additionalPropertiesSchema);
1153         } else
1154            throw new BeanRuntimeException(JsonSchemaProperty.class,
1155               "Invalid attribute type ''{0}'' passed in.  Must be one of the following:  Boolean, JsonSchema",
1156               additionalProperties.getClass().getName());
1157      }
1158      return this;
1159   }
1160
1161   /**
1162    * Used during parsing to convert the <property>additionalProperties</property> property to the correct class type.
1163    *
1164    * <ul class='spaced-list'>
1165    *    <li>
1166    *       If parsing a JSON-object, converts to a {@link JsonSchema}.
1167    *    <li>
1168    *       If parsing a JSON-boolean, converts to a {@link Boolean}.
1169    * </ul>
1170    *
1171    * <p>
1172    * Serialization method is a no-op.
1173    */
1174   public static class BooleanOrSchemaSwap extends PojoSwap<Object,Object> {
1175
1176      @Override /* PojoSwap */
1177      public Object swap(BeanSession session, Object o) throws SerializeException {
1178         return o;
1179      }
1180
1181      @Override /* PojoSwap */
1182      public Object unswap(BeanSession session, Object o, ClassMeta<?> hint) throws ParseException {
1183         ClassMeta<?> cm = (
1184            o instanceof Boolean
1185            ? session.getClassMeta(Boolean.class)
1186            : session.getClassMeta(JsonSchema.class)
1187         );
1188         return session.convertToType(o, cm);
1189      }
1190   }
1191
1192   /**
1193    * Bean property getter:  <property>enum</property>.
1194    *
1195    * @return The value of the <property>enum</property> property on this bean, or <jk>null</jk> if it is not set.
1196    */
1197   public List<String> getEnum() {
1198      return _enum;
1199   }
1200
1201   /**
1202    * Bean property setter:  <property>enum</property>.
1203    *
1204    * @param _enum The new value for the <property>enum</property> property on this bean.
1205    * @return This object (for method chaining).
1206    */
1207   public JsonSchema setEnum(List<String> _enum) {
1208      this._enum = _enum;
1209      return this;
1210   }
1211
1212   /**
1213    * Bean property appender:  <property>enum</property>.
1214    *
1215    * @param _enum The list of items to append to the <property>enum</property> property on this bean.
1216    * @return This object (for method chaining).
1217    */
1218   public JsonSchema addEnum(String..._enum) {
1219      if (this._enum == null)
1220         this._enum = new LinkedList<>();
1221      for (String e : _enum)
1222         this._enum.add(e);
1223      return this;
1224   }
1225
1226   /**
1227    * Bean property getter:  <property>allOf</property>.
1228    *
1229    * @return The value of the <property>allOf</property> property on this bean, or <jk>null</jk> if it is not set.
1230    */
1231   public List<JsonSchema> getAllOf() {
1232      return allOf;
1233   }
1234
1235   /**
1236    * Bean property setter:  <property>allOf</property>.
1237    *
1238    * @param allOf The new value for the <property>allOf</property> property on this bean.
1239    * @return This object (for method chaining).
1240    */
1241   public JsonSchema setAllOf(List<JsonSchema> allOf) {
1242      this.allOf = allOf;
1243      setMasterOn(allOf);
1244      return this;
1245   }
1246
1247   /**
1248    * Bean property appender:  <property>allOf</property>.
1249    *
1250    * @param allOf The list of items to append to the <property>allOf</property> property on this bean.
1251    * @return This object (for method chaining).
1252    */
1253   public JsonSchema addAllOf(JsonSchema...allOf) {
1254      if (this.allOf == null)
1255         this.allOf = new LinkedList<>();
1256      setMasterOn(allOf);
1257      for (JsonSchema s : allOf)
1258         this.allOf.add(s);
1259      return this;
1260   }
1261
1262   /**
1263    * Bean property getter:  <property>anyOf</property>.
1264    *
1265    * @return The value of the <property>anyOf</property> property on this bean, or <jk>null</jk> if it is not set.
1266    */
1267   public List<JsonSchema> getAnyOf() {
1268      return anyOf;
1269   }
1270
1271   /**
1272    * Bean property setter:  <property>anyOf</property>.
1273    *
1274    * @param anyOf The new value of the <property>anyOf</property> property on this bean.
1275    * @return This object (for method chaining).
1276    */
1277   public JsonSchema setAnyOf(List<JsonSchema> anyOf) {
1278      this.anyOf = anyOf;
1279      setMasterOn(anyOf);
1280      return this;
1281   }
1282
1283   /**
1284    * Bean property appender:  <property>anyOf</property>.
1285    *
1286    * @param anyOf The list of items to append to the <property>anyOf</property> property on this bean.
1287    * @return This object (for method chaining).
1288    */
1289   public JsonSchema addAnyOf(JsonSchema...anyOf) {
1290      if (this.anyOf == null)
1291         this.anyOf = new LinkedList<>();
1292      setMasterOn(anyOf);
1293      for (JsonSchema s : anyOf)
1294         this.anyOf.add(s);
1295      return this;
1296   }
1297
1298   /**
1299    * Bean property getter:  <property>oneOf</property>.
1300    *
1301    * @return The value of the <property>oneOf</property> property on this bean, or <jk>null</jk> if it is not set.
1302    */
1303   public List<JsonSchema> getOneOf() {
1304      return oneOf;
1305   }
1306
1307   /**
1308    * Bean property setter:  <property>oneOf</property>.
1309    *
1310    * @param oneOf The new value for the <property>oneOf</property> property on this bean.
1311    * @return This object (for method chaining).
1312    */
1313   public JsonSchema setOneOf(List<JsonSchema> oneOf) {
1314      this.oneOf = oneOf;
1315      setMasterOn(oneOf);
1316      return this;
1317   }
1318
1319   /**
1320    * Bean property appender:  <property>oneOf</property>.
1321    *
1322    * @param oneOf The list of items to append to the <property>oneOf</property> property on this bean.
1323    * @return This object (for method chaining).
1324    */
1325   public JsonSchema addOneOf(JsonSchema...oneOf) {
1326      if (this.oneOf == null)
1327         this.oneOf = new LinkedList<>();
1328      setMasterOn(oneOf);
1329      for (JsonSchema s : oneOf)
1330         this.oneOf.add(s);
1331      return this;
1332   }
1333
1334   /**
1335    * Bean property getter:  <property>not</property>.
1336    *
1337    * @return The value of the <property>not</property> property on this bean, or <jk>null</jk> if it is not set.
1338    */
1339   public JsonSchema getNot() {
1340      return not;
1341   }
1342
1343   /**
1344    * Bean property setter:  <property>not</property>.
1345    *
1346    * @param not The new value for the <property>not</property> property on this bean.
1347    * @return This object (for method chaining).
1348    */
1349   public JsonSchema setNot(JsonSchema not) {
1350      this.not = not;
1351      setMasterOn(not);
1352      return this;
1353   }
1354
1355   /**
1356    * Bean property getter:  <property>$ref</property>.
1357    *
1358    * @return The value of the <property>$ref</property> property on this bean, or <jk>null</jk> if it is not set.
1359    */
1360   @Beanp("$ref")
1361   public URI getRef() {
1362      return ref;
1363   }
1364
1365   /**
1366    * Bean property setter:  <property>$ref</property>.
1367    *
1368    * <p>
1369    * The value can be of any of the following types: {@link URI}, {@link URL}, {@link String}.
1370    * Strings must be valid URIs.
1371    *
1372    * <p>
1373    * URIs defined by {@link UriResolver} can be used for values.
1374    *
1375    * @param ref The new value for the <property>$ref</property> property on this bean.
1376    * @return This object (for method chaining).
1377    */
1378   @Beanp("$ref")
1379   public JsonSchema setRef(Object ref) {
1380      this.ref = toURI(ref);
1381      return this;
1382   }
1383
1384   private void setMasterOn(JsonSchema s) {
1385      if (s != null)
1386         s.setMaster(this);
1387   }
1388
1389   private void setMasterOn(JsonSchema[] ss) {
1390      if (ss != null)
1391         for (JsonSchema s : ss)
1392            setMasterOn(s);
1393   }
1394
1395   private void setMasterOn(Collection<JsonSchema> ss) {
1396      if (ss != null)
1397         for (JsonSchema s : ss)
1398            setMasterOn(s);
1399   }
1400
1401   private void setMasterOn(JsonSchemaArray ss) {
1402      if (ss != null)
1403         for (JsonSchema s : ss)
1404            setMasterOn(s);
1405   }
1406
1407   /**
1408    * Sets the master schema for this schema and all child schema objects.
1409    *
1410    * <p>
1411    * All child elements in a schema should point to a single "master" schema in order to locate registered JsonSchemaMap
1412    * objects for resolving external schemas.
1413    *
1414    * @param master The master schema to associate on this and all children.  Can be <jk>null</jk>.
1415    */
1416   protected void setMaster(JsonSchema master) {
1417      this.master = master;
1418      if (definitions != null)
1419         for (JsonSchema s : definitions.values())
1420            s.setMaster(master);
1421      if (properties != null)
1422         for (JsonSchema s : properties.values())
1423            s.setMaster(master);
1424      if (patternProperties != null)
1425         for (JsonSchema s : patternProperties.values())
1426            s.setMaster(master);
1427      if (dependencies != null)
1428         for (JsonSchema s : dependencies.values())
1429            s.setMaster(master);
1430      if (itemsSchema != null)
1431         itemsSchema.setMaster(master);
1432      if (itemsSchemaArray != null)
1433         for (JsonSchema s : itemsSchemaArray)
1434            s.setMaster(master);
1435      if (additionalItemsSchemaArray != null)
1436         for (JsonSchema s : additionalItemsSchemaArray)
1437            s.setMaster(master);
1438      if (additionalPropertiesSchema != null)
1439         additionalPropertiesSchema.setMaster(master);
1440      if (allOf != null)
1441         for (JsonSchema s : allOf)
1442            s.setMaster(master);
1443      if (anyOf != null)
1444         for (JsonSchema s : anyOf)
1445            s.setMaster(master);
1446      if (oneOf != null)
1447         for (JsonSchema s : oneOf)
1448            s.setMaster(master);
1449      if (not != null)
1450         not.setMaster(master);
1451   }
1452
1453   /**
1454    * Resolve schema if reference.
1455    *
1456    * <p>
1457    * If this schema is a reference to another schema (has its <property>$ref</property> property set), this
1458    * method will retrieve the referenced schema from the schema map registered with this schema.
1459    *
1460    * <p>
1461    * If this schema is not a reference, or no schema map is registered with this schema, this method is a no-op and
1462    * simply returns this object.
1463    *
1464    * @return The referenced schema, or <jk>null</jk>.
1465    */
1466   public JsonSchema resolve() {
1467      if (ref == null || master.schemaMap == null)
1468         return this;
1469      return master.schemaMap.get(ref);
1470   }
1471
1472   /**
1473    * Associates a schema map with this schema for resolving other schemas identified through <property>$ref</property>
1474    * properties.
1475    *
1476    * @param schemaMap The schema map to associate with this schema.  Can be <jk>null</jk>.
1477    * @return This object (for method chaining).
1478    */
1479   public JsonSchema setSchemaMap(JsonSchemaMap schemaMap) {
1480      this.schemaMap = schemaMap;
1481      return this;
1482   }
1483
1484   @Override /* Object */
1485   public String toString() {
1486      return JsonSerializer.DEFAULT.toString(this);
1487   }
1488}