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