001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.bean.swagger;
018
019import static org.apache.juneau.commons.utils.AssertionUtils.*;
020import static org.apache.juneau.commons.utils.CollectionUtils.*;
021import static org.apache.juneau.commons.utils.Utils.*;
022import static org.apache.juneau.internal.ConverterUtils.*;
023
024import java.util.*;
025
026import org.apache.juneau.annotation.*;
027import org.apache.juneau.commons.collections.*;
028
029/**
030 * Allows the definition of input and output data types.
031 *
032 * <p>
033 * The Schema Object allows the definition of input and output data types for Swagger 2.0, including objects,
034 * primitives, and arrays. This object is an extended subset of the JSON Schema Specification Draft 4, with
035 * additional extensions provided by the Swagger Specification to allow for more complete documentation.
036 *
037 * <h5 class='section'>Swagger Specification:</h5>
038 * <p>
039 * The Schema Object supports all properties from JSON Schema Draft 4, including but not limited to:
040 * <ul class='spaced-list'>
041 *    <li><c>type</c> (string) - The data type. Values: <js>"string"</js>, <js>"number"</js>, <js>"integer"</js>, <js>"boolean"</js>, <js>"array"</js>, <js>"object"</js>, <js>"file"</js>
042 *    <li><c>format</c> (string) - The format modifier (e.g., <js>"int32"</js>, <js>"int64"</js>, <js>"float"</js>, <js>"double"</js>, <js>"date"</js>, <js>"date-time"</js>)
043 *    <li><c>title</c> (string) - A short title for the schema
044 *    <li><c>description</c> (string) - A description of the schema
045 *    <li><c>default</c> (any) - The default value
046 *    <li><c>multipleOf</c> (number) - Must be a multiple of this value
047 *    <li><c>maximum</c> (number) - Maximum value (inclusive by default)
048 *    <li><c>exclusiveMaximum</c> (boolean) - If true, maximum is exclusive
049 *    <li><c>minimum</c> (number) - Minimum value (inclusive by default)
050 *    <li><c>exclusiveMinimum</c> (boolean) - If true, minimum is exclusive
051 *    <li><c>maxLength</c> (integer) - Maximum string length
052 *    <li><c>minLength</c> (integer) - Minimum string length
053 *    <li><c>pattern</c> (string) - Regular expression pattern the string must match
054 *    <li><c>maxItems</c> (integer) - Maximum array length
055 *    <li><c>minItems</c> (integer) - Minimum array length
056 *    <li><c>uniqueItems</c> (boolean) - If true, array items must be unique
057 *    <li><c>maxProperties</c> (integer) - Maximum number of object properties
058 *    <li><c>minProperties</c> (integer) - Minimum number of object properties
059 *    <li><c>required</c> (array of string) - Required property names
060 *    <li><c>enum</c> (array) - Possible values for this schema
061 *    <li><c>properties</c> (map of {@link SchemaInfo}) - Object property definitions
062 *    <li><c>items</c> ({@link Items}) - Schema for array items
063 *    <li><c>allOf</c> (array of {@link SchemaInfo}) - Must validate against all schemas
064 *    <li><c>discriminator</c> (string) - Property name for polymorphism (Swagger extension)
065 *    <li><c>readOnly</c> (boolean) - Relevant only for Schema properties (Swagger extension)
066 *    <li><c>xml</c> ({@link Xml}) - XML representation details (Swagger extension)
067 *    <li><c>externalDocs</c> ({@link ExternalDocumentation}) - Additional external documentation (Swagger extension)
068 *    <li><c>example</c> (any) - Example value (Swagger extension)
069 * </ul>
070 *
071 * <h5 class='section'>Example:</h5>
072 * <p class='bjava'>
073 *    <jc>// Construct using SwaggerBuilder.</jc>
074 *    SchemaInfo <jv>info</jv> = <jsm>schemaInfo</jsm>()
075 *       .type(<js>"string"</js>)
076 *       .title(<js>"foo"</js>)
077 *
078 *    <jc>// Serialize using JsonSerializer.</jc>
079 *    String <jv>json</jv> = Json.<jsm>from</jsm>(<jv>info</jv>);
080 *
081 *    <jc>// Or just use toString() which does the same as above.</jc>
082 *    <jv>json</jv> = <jv>info</jv>.toString();
083 * </p>
084 * <p class='bjson'>
085 *    <jc>// Output</jc>
086 *    {
087 *       <js>"type"</js>: <js>"string"</js>,
088 *       <js>"title"</js>: <js>"foo"</js>
089 *    }
090 * </p>
091 *
092 * <h5 class='section'>See Also:</h5><ul>
093 *    <li class='link'><a class="doclink" href="https://swagger.io/specification/v2/#schema-object">Swagger 2.0 Specification &gt; Schema Object</a>
094 *    <li class='link'><a class="doclink" href="https://swagger.io/docs/specification/2-0/data-models/">Swagger Data Models</a>
095 *    <li class='link'><a class="doclink" href="https://json-schema.org/">JSON Schema Specification</a>
096 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanSwagger2">juneau-bean-swagger-v2</a>
097 * </ul>
098 */
099public class SchemaInfo extends SwaggerElement {
100
101   private String format, title, description, pattern, type, discriminator, ref;
102   private Number multipleOf, maximum, minimum;
103   private Integer maxLength, minLength, maxItems, minItems, maxProperties, minProperties;
104   private Boolean exclusiveMaximum, exclusiveMinimum, uniqueItems, readOnly, required;
105   private Object default_,
106      example;
107   private Items items;
108   private Xml xml;
109   private ExternalDocumentation externalDocs;
110   private Set<Object> enum_ = new LinkedHashSet<>();
111   private Set<SchemaInfo> allOf = new LinkedHashSet<>();
112   private Set<String> requiredProperties = new LinkedHashSet<>();
113   private Map<String,SchemaInfo> properties = map();
114   private SchemaInfo additionalProperties;
115
116   /**
117    * Default constructor.
118    */
119   public SchemaInfo() {}
120
121   /**
122    * Copy constructor.
123    *
124    * @param copyFrom The object to copy.
125    */
126   public SchemaInfo(SchemaInfo copyFrom) {
127      super(copyFrom);
128
129      this.additionalProperties = copyFrom.additionalProperties == null ? null : copyFrom.additionalProperties.copy();
130      if (nn(copyFrom.allOf))
131         this.allOf.addAll(copyOf(copyFrom.allOf, SchemaInfo::copy));
132      this.default_ = copyFrom.default_;
133      this.description = copyFrom.description;
134      this.discriminator = copyFrom.discriminator;
135      if (nn(copyFrom.enum_))
136         this.enum_.addAll(copyOf(copyFrom.enum_));
137      this.example = copyFrom.example;
138      this.exclusiveMaximum = copyFrom.exclusiveMaximum;
139      this.exclusiveMinimum = copyFrom.exclusiveMinimum;
140      this.externalDocs = copyFrom.externalDocs == null ? null : copyFrom.externalDocs.copy();
141      this.format = copyFrom.format;
142      this.items = copyFrom.items == null ? null : copyFrom.items.copy();
143      this.maximum = copyFrom.maximum;
144      this.maxItems = copyFrom.maxItems;
145      this.maxLength = copyFrom.maxLength;
146      this.maxProperties = copyFrom.maxProperties;
147      this.minimum = copyFrom.minimum;
148      this.minItems = copyFrom.minItems;
149      this.minLength = copyFrom.minLength;
150      this.minProperties = copyFrom.minProperties;
151      this.multipleOf = copyFrom.multipleOf;
152      this.pattern = copyFrom.pattern;
153      this.readOnly = copyFrom.readOnly;
154      this.ref = copyFrom.ref;
155      this.required = copyFrom.required;
156      if (nn(copyFrom.requiredProperties))
157         this.requiredProperties.addAll(copyOf(copyFrom.requiredProperties));
158      this.title = copyFrom.title;
159      this.type = copyFrom.type;
160      this.uniqueItems = copyFrom.uniqueItems;
161      this.xml = copyFrom.xml == null ? null : copyFrom.xml.copy();
162      if (nn(copyFrom.properties))
163         properties.putAll(copyOf(copyFrom.properties, SchemaInfo::copy));
164   }
165
166   /**
167    * Bean property fluent setter:  <property>allOf</property>.
168    *
169    * <p>
170    * Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema.
171    *
172    * @param values
173    *    The values to add to this property.
174    *    <br>Ignored if <jk>null</jk>.
175    * @return This object.
176    */
177   public SchemaInfo addAllOf(Collection<SchemaInfo> values) {
178      if (nn(values))
179         for (var v : values)
180            if (nn(v))
181               allOf.add(v);
182      return this;
183   }
184
185   /**
186    * Bean property appender:  <property>allOf</property>.
187    *
188    * @param values
189    *    The values to add to this property.
190    *    <br>Ignored if <jk>null</jk>.
191    * @return This object.
192    */
193   public SchemaInfo addAllOf(SchemaInfo...values) {
194      if (nn(values))
195         for (var v : values)
196            if (nn(v))
197               allOf.add(v);
198      return this;
199   }
200
201   /**
202    * Bean property fluent setter:  <property>enum</property>.
203    *
204    * <p>
205    * An enumeration of possible values.
206    *
207    * @param values
208    *    The values to add to this property.
209    *    <br>Ignored if <jk>null</jk>.
210    * @return This object.
211    */
212   public SchemaInfo addEnum(Collection<Object> values) {
213      if (nn(values))
214         enum_.addAll(values);
215      return this;
216   }
217
218   /**
219    * Bean property appender:  <property>enum</property>.
220    *
221    * @param value
222    *    The values to add to this property.
223    *    <br>Ignored if <jk>null</jk>.
224    * @return This object.
225    */
226   public SchemaInfo addEnum(Object...value) {
227      if (nn(value))
228         for (var v : value)
229            if (nn(v))
230               enum_.add(v);
231      return this;
232   }
233
234   /**
235    * Bean property appender:  <property>properties</property>.
236    *
237    * @param key The property key.  Must not be <jk>null</jk>.
238    * @param value The property value.  Must not be <jk>null</jk>.
239    * @return This object.
240    */
241   public SchemaInfo addProperty(String key, SchemaInfo value) {
242      assertArgNotNull("key", key);
243      assertArgNotNull("value", value);
244      properties.put(key, value);
245      return this;
246   }
247
248   /**
249    * Bean property fluent setter:  <property>requiredProperties</property>.
250    *
251    * <p>
252    * Takes an array of strings that define the required properties.
253    *
254    * @param values
255    *    The values to add to this property.
256    *    <br>Ignored if <jk>null</jk>.
257    * @return This object.
258    */
259   public SchemaInfo addRequiredProperties(Collection<String> values) {
260      if (nn(values))
261         requiredProperties.addAll(values);
262      return this;
263   }
264
265   /**
266    * Bean property appender:  <property>requiredProperties</property>.
267    *
268    * <p>
269    * The list of required properties.
270    *
271    * @param value
272    *    The values to add to this property.
273    *    <br>Ignored if <jk>null</jk>.
274    * @return This object.
275    */
276   public SchemaInfo addRequiredProperties(String...value) {
277      if (nn(value))
278         for (var v : value)
279            if (nn(v))
280               requiredProperties.add(v);
281      return this;
282   }
283
284   /**
285    * Make a deep copy of this object.
286    *
287    * @return A deep copy of this object.
288    */
289   public SchemaInfo copy() {
290      return new SchemaInfo(this);
291   }
292
293   @Override /* Overridden from SwaggerElement */
294   public <T> T get(String property, Class<T> type) {
295      assertArgNotNull("property", property);
296      return switch (property) {  // NOSONAR
297         case "additionalProperties" -> toType(getAdditionalProperties(), type);
298         case "allOf" -> toType(getAllOf(), type);
299         case "default" -> toType(getDefault(), type);
300         case "description" -> toType(getDescription(), type);
301         case "discriminator" -> toType(getDiscriminator(), type);
302         case "enum" -> toType(getEnum(), type);
303         case "example" -> toType(getExample(), type);
304         case "exclusiveMaximum" -> toType(getExclusiveMaximum(), type);
305         case "exclusiveMinimum" -> toType(getExclusiveMinimum(), type);
306         case "externalDocs" -> toType(getExternalDocs(), type);
307         case "format" -> toType(getFormat(), type);
308         case "items" -> toType(getItems(), type);
309         case "maximum" -> toType(getMaximum(), type);
310         case "maxItems" -> toType(getMaxItems(), type);
311         case "maxLength" -> toType(getMaxLength(), type);
312         case "maxProperties" -> toType(getMaxProperties(), type);
313         case "minimum" -> toType(getMinimum(), type);
314         case "minItems" -> toType(getMinItems(), type);
315         case "minLength" -> toType(getMinLength(), type);
316         case "minProperties" -> toType(getMinProperties(), type);
317         case "multipleOf" -> toType(getMultipleOf(), type);
318         case "pattern" -> toType(getPattern(), type);
319         case "properties" -> toType(getProperties(), type);
320         case "readOnly" -> toType(getReadOnly(), type);
321         case "$ref" -> toType(getRef(), type);
322         case "required" -> toType(getRequired(), type);
323         case "requiredProperties" -> toType(getRequiredProperties(), type);
324         case "title" -> toType(getTitle(), type);
325         case "type" -> toType(getType(), type);
326         case "uniqueItems" -> toType(getUniqueItems(), type);
327         case "xml" -> toType(getXml(), type);
328         default -> super.get(property, type);
329      };
330   }
331
332   /**
333    * Bean property getter:  <property>additionalProperties</property>.
334    *
335    * @return The property value, or <jk>null</jk> if it is not set.
336    */
337   public SchemaInfo getAdditionalProperties() { return additionalProperties; }
338
339   /**
340    * Bean property getter:  <property>allOf</property>.
341    *
342    * @return The property value, or <jk>null</jk> if it is not set.
343    */
344   public Set<SchemaInfo> getAllOf() { return nullIfEmpty(allOf); }
345
346   /**
347    * Bean property getter:  <property>default</property>.
348    *
349    * <p>
350    * Unlike JSON Schema, the value MUST conform to the defined type for the Schema Object.
351    *
352    * @return The property value, or <jk>null</jk> if it is not set.
353    */
354   public Object getDefault() { return default_; }
355
356   /**
357    * Bean property getter:  <property>description</property>.
358    *
359    * @return The property value, or <jk>null</jk> if it is not set.
360    */
361   public String getDescription() { return description; }
362
363   /**
364    * Bean property getter:  <property>discriminator</property>.
365    *
366    * @return The property value, or <jk>null</jk> if it is not set.
367    */
368   public String getDiscriminator() { return discriminator; }
369
370   /**
371    * Bean property getter:  <property>enum</property>.
372    *
373    * @return The property value, or <jk>null</jk> if it is not set.
374    */
375   public Set<Object> getEnum() { return nullIfEmpty(enum_); }
376
377   /**
378    * Bean property getter:  <property>example</property>.
379    *
380    * @return The property value, or <jk>null</jk> if it is not set.
381    */
382   public Object getExample() { return example; }
383
384   /**
385    * Bean property getter:  <property>exclusiveMaximum</property>.
386    *
387    * @return The property value, or <jk>null</jk> if it is not set.
388    */
389   public Boolean getExclusiveMaximum() { return exclusiveMaximum; }
390
391   /**
392    * Bean property getter:  <property>exclusiveMinimum</property>.
393    *
394    * @return The property value, or <jk>null</jk> if it is not set.
395    */
396   public Boolean getExclusiveMinimum() { return exclusiveMinimum; }
397
398   /**
399    * Bean property getter:  <property>externalDocs</property>.
400    *
401    * @return The property value, or <jk>null</jk> if it is not set.
402    */
403   public ExternalDocumentation getExternalDocs() { return externalDocs; }
404
405   /**
406    * Bean property getter:  <property>format</property>.
407    *
408    * @return The property value, or <jk>null</jk> if it is not set.
409    */
410   public String getFormat() { return format; }
411
412   /**
413    * Bean property getter:  <property>items</property>.
414    *
415    * @return The property value, or <jk>null</jk> if it is not set.
416    */
417   public Items getItems() { return items; }
418
419   /**
420    * Bean property getter:  <property>maximum</property>.
421    *
422    * @return The property value, or <jk>null</jk> if it is not set.
423    */
424   public Number getMaximum() { return maximum; }
425
426   /**
427    * Bean property getter:  <property>maxItems</property>.
428    *
429    * @return The property value, or <jk>null</jk> if it is not set.
430    */
431   public Integer getMaxItems() { return maxItems; }
432
433   /**
434    * Bean property getter:  <property>maxLength</property>.
435    *
436    * @return The property value, or <jk>null</jk> if it is not set.
437    */
438   public Integer getMaxLength() { return maxLength; }
439
440   /**
441    * Bean property getter:  <property>maxProperties</property>.
442    *
443    * @return The property value, or <jk>null</jk> if it is not set.
444    */
445   public Integer getMaxProperties() { return maxProperties; }
446
447   /**
448    * Bean property getter:  <property>minimum</property>.
449    *
450    * @return The property value, or <jk>null</jk> if it is not set.
451    */
452   public Number getMinimum() { return minimum; }
453
454   /**
455    * Bean property getter:  <property>minItems</property>.
456    *
457    * @return The property value, or <jk>null</jk> if it is not set.
458    */
459   public Integer getMinItems() { return minItems; }
460
461   /**
462    * Bean property getter:  <property>minLength</property>.
463    *
464    * @return The property value, or <jk>null</jk> if it is not set.
465    */
466   public Integer getMinLength() { return minLength; }
467
468   /**
469    * Bean property getter:  <property>minProperties</property>.
470    *
471    * @return The property value, or <jk>null</jk> if it is not set.
472    */
473   public Integer getMinProperties() { return minProperties; }
474
475   /**
476    * Bean property getter:  <property>multipleOf</property>.
477    *
478    * @return The property value, or <jk>null</jk> if it is not set.
479    */
480   public Number getMultipleOf() { return multipleOf; }
481
482   /**
483    * Bean property getter:  <property>pattern</property>.
484    *
485    * @return The property value, or <jk>null</jk> if it is not set.
486    */
487   public String getPattern() { return pattern; }
488
489   /**
490    * Bean property getter:  <property>properties</property>.
491    *
492    * @return The property value, or <jk>null</jk> if it is not set.
493    */
494   public Map<String,SchemaInfo> getProperties() { return nullIfEmpty(properties); }
495
496   /**
497    * Bean property getter:  <property>readOnly</property>.
498    *
499    * @return The property value, or <jk>null</jk> if it is not set.
500    */
501   public Boolean getReadOnly() { return readOnly; }
502
503   /**
504    * Bean property getter:  <property>$ref</property>.
505    *
506    * @return The property value, or <jk>null</jk> if it is not set.
507    */
508   @Beanp("$ref")
509   public String getRef() { return ref; }
510
511   /**
512    * Bean property getter:  <property>required</property>.
513    *
514    * @return The property value, or <jk>null</jk> if it is not set.
515    */
516   public Boolean getRequired() { return required; }
517
518   /**
519    * Bean property getter:  <property>requiredProperties</property>.
520    *
521    * <p>
522    * The list of required properties.
523    *
524    * @return The property value, or <jk>null</jk> if it is not set.
525    */
526   public Set<String> getRequiredProperties() { return nullIfEmpty(requiredProperties); }
527
528   /**
529    * Bean property getter:  <property>title</property>.
530    *
531    * @return The property value, or <jk>null</jk> if it is not set.
532    */
533   public String getTitle() { return title; }
534
535   /**
536    * Bean property getter:  <property>type</property>.
537    *
538    * @return The property value, or <jk>null</jk> if it is not set.
539    */
540   public String getType() { return type; }
541
542   /**
543    * Bean property getter:  <property>uniqueItems</property>.
544    *
545    * @return The property value, or <jk>null</jk> if it is not set.
546    */
547   public Boolean getUniqueItems() { return uniqueItems; }
548
549   /**
550    * Bean property getter:  <property>xml</property>.
551    *
552    * @return The property value, or <jk>null</jk> if it is not set.
553    */
554   public Xml getXml() { return xml; }
555
556   @Override /* Overridden from SwaggerElement */
557   public Set<String> keySet() {
558      // @formatter:off
559      var s = setb(String.class)
560         .addIf(nn(ref), "$ref")
561         .addIf(nn(additionalProperties), "additionalProperties")
562         .addIf(ne(allOf), "allOf")
563         .addIf(nn(default_), "default")
564         .addIf(nn(description), "description")
565         .addIf(nn(discriminator), "discriminator")
566         .addIf(ne(enum_), "enum")
567         .addIf(nn(example), "example")
568         .addIf(nn(exclusiveMaximum), "exclusiveMaximum")
569         .addIf(nn(exclusiveMinimum), "exclusiveMinimum")
570         .addIf(nn(externalDocs), "externalDocs")
571         .addIf(nn(format), "format")
572         .addIf(nn(items), "items")
573         .addIf(nn(maxItems), "maxItems")
574         .addIf(nn(maxLength), "maxLength")
575         .addIf(nn(maxProperties), "maxProperties")
576         .addIf(nn(maximum), "maximum")
577         .addIf(nn(minItems), "minItems")
578         .addIf(nn(minLength), "minLength")
579         .addIf(nn(minProperties), "minProperties")
580         .addIf(nn(minimum), "minimum")
581         .addIf(nn(multipleOf), "multipleOf")
582         .addIf(nn(pattern), "pattern")
583         .addIf(ne(properties), "properties")
584         .addIf(nn(readOnly), "readOnly")
585         .addIf(nn(required), "required")
586         .addIf(ne(requiredProperties), "requiredProperties")
587         .addIf(nn(title), "title")
588         .addIf(nn(type), "type")
589         .addIf(nn(uniqueItems), "uniqueItems")
590         .addIf(nn(xml), "xml")
591         .build();
592      // @formatter:on
593      return new MultiSet<>(s, super.keySet());
594   }
595
596   /**
597    * Resolves any <js>"$ref"</js> attributes in this element.
598    *
599    * @param swagger The swagger document containing the definitions.
600    * @param refStack Keeps track of previously-visited references so that we don't cause recursive loops.
601    * @param maxDepth
602    *    The maximum depth to resolve references.
603    *    <br>After that level is reached, <c>$ref</c> references will be left alone.
604    *    <br>Useful if you have very complex models and you don't want your swagger page to be overly-complex.
605    * @return
606    *    This object with references resolved.
607    *    <br>May or may not be the same object.
608    */
609   public SchemaInfo resolveRefs(Swagger swagger, Deque<String> refStack, int maxDepth) {
610
611      if (nn(ref)) {
612         if (refStack.contains(ref) || refStack.size() >= maxDepth)
613            return this;
614         refStack.addLast(ref);
615         var r = swagger.findRef(ref, SchemaInfo.class).resolveRefs(swagger, refStack, maxDepth);
616         refStack.removeLast();
617         return r;
618      }
619
620      if (nn(items))
621         items = items.resolveRefs(swagger, refStack, maxDepth);
622
623      properties.entrySet().forEach(x -> x.setValue(x.getValue().resolveRefs(swagger, refStack, maxDepth)));
624
625      if (nn(additionalProperties))
626         additionalProperties = additionalProperties.resolveRefs(swagger, refStack, maxDepth);
627
628      this.example = null;
629
630      return this;
631   }
632
633   @Override /* Overridden from SwaggerElement */
634   public SchemaInfo set(String property, Object value) {
635      assertArgNotNull("property", property);
636      return switch (property) {  // NOSONAR
637         case "additionalProperties" -> setAdditionalProperties(toType(value, SchemaInfo.class));
638         case "allOf" -> setAllOf(toSetBuilder(value, SchemaInfo.class).sparse().build());
639         case "default" -> setDefault(value);
640         case "description" -> setDescription(s(value));
641         case "discriminator" -> setDiscriminator(s(value));
642         case "enum" -> setEnum(value);
643         case "example" -> setExample(value);
644         case "exclusiveMaximum" -> setExclusiveMaximum(toBoolean(value));
645         case "exclusiveMinimum" -> setExclusiveMinimum(toBoolean(value));
646         case "externalDocs" -> setExternalDocs(toType(value, ExternalDocumentation.class));
647         case "format" -> setFormat(s(value));
648         case "items" -> setItems(toType(value, Items.class));
649         case "maximum" -> setMaximum(toNumber(value));
650         case "maxItems" -> setMaxItems(toInteger(value));
651         case "maxLength" -> setMaxLength(toInteger(value));
652         case "maxProperties" -> setMaxProperties(toInteger(value));
653         case "minimum" -> setMinimum(toNumber(value));
654         case "minItems" -> setMinItems(toInteger(value));
655         case "minLength" -> setMinLength(toInteger(value));
656         case "minProperties" -> setMinProperties(toInteger(value));
657         case "multipleOf" -> setMultipleOf(toNumber(value));
658         case "pattern" -> setPattern(s(value));
659         case "properties" -> setProperties(toMapBuilder(value, String.class, SchemaInfo.class).sparse().build());
660         case "readOnly" -> setReadOnly(toBoolean(value));
661         case "$ref" -> setRef(s(value));
662         case "required" -> setRequired(toBoolean(value));
663         case "requiredProperties" -> setRequiredProperties(listb(String.class).addAny(value).sparse().build());
664         case "title" -> setTitle(s(value));
665         case "type" -> setType(s(value));
666         case "uniqueItems" -> setUniqueItems(toBoolean(value));
667         case "xml" -> setXml(toType(value, Xml.class));
668         default -> {
669            super.set(property, value);
670            yield this;
671         }
672      };
673   }
674
675   /**
676    * Bean property setter:  <property>additionalProperties</property>.
677    *
678    * @param value
679    *    The new value for this property.
680    *    <br>Can be <jk>null</jk> to unset the property.
681    * @return This object.
682    */
683   public SchemaInfo setAdditionalProperties(SchemaInfo value) {
684      additionalProperties = value;
685      return this;
686   }
687
688   /**
689    * Bean property setter:  <property>allOf</property>.
690    *
691    * @param value
692    *    The new value for this property.
693    *    <br>Can be <jk>null</jk> to unset the property.
694    * @return This object.
695    */
696   public SchemaInfo setAllOf(Collection<SchemaInfo> value) {
697      allOf.clear();
698      if (nn(value))
699         allOf.addAll(value);
700      return this;
701   }
702
703   /**
704    * Bean property fluent setter:  <property>allOf</property>.
705    *
706    * @param value
707    *    The new value for this property.
708    *    <br>Strings can contains JSON arrays.
709    *    <br>Valid types:
710    * @return This object.
711    */
712   public SchemaInfo setAllOf(SchemaInfo...value) {
713      setAllOf(setb(SchemaInfo.class).sparse().addAny((Object[])value).build());
714      return this;
715   }
716
717   /**
718    * Bean property setter:  <property>default</property>.
719    *
720    * <p>
721    * Unlike JSON Schema, the value MUST conform to the defined type for the Schema Object.
722    *
723    * @param value
724    *    The new value for this property.
725    *    <br>Can be <jk>null</jk> to unset the property.
726    * @return This object.
727    */
728   public SchemaInfo setDefault(Object value) {
729      default_ = value;
730      return this;
731   }
732
733   /**
734    * Bean property setter:  <property>description</property>.
735    *
736    * @param value
737    *    The new value for this property.
738    *    <br><a class="doclink" href="https://help.github.com/articles/github-flavored-markdown">GFM syntax</a> can be used for rich text representation.
739    *    <br>Can be <jk>null</jk> to unset the property.
740    * @return This object.
741    */
742   public SchemaInfo setDescription(String value) {
743      description = value;
744      return this;
745   }
746
747   /**
748    * Bean property setter:  <property>discriminator</property>.
749    *
750    * @param value
751    *    The new value for this property.
752    *    <br>Can be <jk>null</jk> to unset the property.
753    * @return This object.
754    */
755   public SchemaInfo setDiscriminator(String value) {
756      discriminator = value;
757      return this;
758   }
759
760   /**
761    * Bean property setter:  <property>enum</property>.
762    *
763    * @param value
764    *    The new value for this property.
765    *    <br>Can be <jk>null</jk> to unset the property.
766    * @return This object.
767    */
768   public SchemaInfo setEnum(Collection<Object> value) {
769      enum_.clear();
770      if (nn(value))
771         enum_.addAll(value);
772      return this;
773   }
774
775   /**
776    * Bean property fluent setter:  <property>enum</property>.
777    *
778    * @param value
779    *    The new value for this property.
780    *    <br>Strings can be JSON arrays.
781    * @return This object.
782    */
783   public SchemaInfo setEnum(Object...value) {
784      setEnum(setb(Object.class).sparse().addAny(value).build());
785      return this;
786   }
787
788   /**
789    * Bean property setter:  <property>example</property>.
790    *
791    * @param value
792    *    The new value for this property.
793    *    <br>Can be <jk>null</jk> to unset the property.
794    * @return This object.
795    */
796   public SchemaInfo setExample(Object value) {
797      example = value;
798      return this;
799   }
800
801   /**
802    * Bean property setter:  <property>exclusiveMaximum</property>.
803    *
804    * @param value
805    *    The new value for this property.
806    *    <br>Can be <jk>null</jk> to unset the property.
807    * @return This object.
808    */
809   public SchemaInfo setExclusiveMaximum(Boolean value) {
810      exclusiveMaximum = value;
811      return this;
812   }
813
814   /**
815    * Bean property setter:  <property>exclusiveMinimum</property>.
816    *
817    * @param value
818    *    The new value for this property.
819    *    <br>Can be <jk>null</jk> to unset the property.
820    * @return This object.
821    */
822   public SchemaInfo setExclusiveMinimum(Boolean value) {
823      exclusiveMinimum = value;
824      return this;
825   }
826
827   /**
828    * Bean property setter:  <property>externalDocs</property>.
829    *
830    * @param value
831    *    The new value for this property.
832    *    <br>Can be <jk>null</jk> to unset the property.
833    * @return This object.
834    */
835   public SchemaInfo setExternalDocs(ExternalDocumentation value) {
836      externalDocs = value;
837      return this;
838   }
839
840   /**
841    * Bean property setter:  <property>format</property>.
842    *
843    * @param value
844    *    The new value for this property.
845    *    <br>Can be <jk>null</jk> to unset the property.
846    *    <br>Formats defined by the OAS include:
847    *    <ul>
848    *       <li><js>"int32"</js>
849    *       <li><js>"int64"</js>
850    *       <li><js>"float"</js>
851    *       <li><js>"double"</js>
852    *       <li><js>"byte"</js>
853    *       <li><js>"binary"</js>
854    *       <li><js>"date"</js>
855    *       <li><js>"date-time"</js>
856    *       <li><js>"password"</js>
857    *    </ul>
858    * @return This object.
859    */
860   public SchemaInfo setFormat(String value) {
861      format = value;
862      return this;
863   }
864
865   /**
866    * Bean property setter:  <property>items</property>.
867    *
868    * @param value
869    *    The new value for this property.
870    *    <br>Can be <jk>null</jk> to unset the property.
871    * @return This object.
872    */
873   public SchemaInfo setItems(Items value) {
874      items = value;
875      return this;
876   }
877
878   /**
879    * Bean property setter:  <property>maximum</property>.
880    *
881    * @param value
882    *    The new value for this property.
883    *    <br>Can be <jk>null</jk> to unset the property.
884    * @return This object.
885    */
886   public SchemaInfo setMaximum(Number value) {
887      maximum = value;
888      return this;
889   }
890
891   /**
892    * Bean property setter:  <property>maxItems</property>.
893    *
894    * @param value
895    *    The new value for this property.
896    *    <br>Can be <jk>null</jk> to unset the property.
897    * @return This object.
898    */
899   public SchemaInfo setMaxItems(Integer value) {
900      maxItems = value;
901      return this;
902   }
903
904   /**
905    * Bean property setter:  <property>maxLength</property>.
906    *
907    * @param value
908    *    The new value for this property.
909    *    <br>Can be <jk>null</jk> to unset the property.
910    * @return This object.
911    */
912   public SchemaInfo setMaxLength(Integer value) {
913      maxLength = value;
914      return this;
915   }
916
917   /**
918    * Bean property setter:  <property>maxProperties</property>.
919    *
920    * @param value
921    *    The new value for this property.
922    *    <br>Can be <jk>null</jk> to unset the property.
923    * @return This object.
924    */
925   public SchemaInfo setMaxProperties(Integer value) {
926      maxProperties = value;
927      return this;
928   }
929
930   /**
931    * Bean property setter:  <property>minimum</property>.
932    *
933    * @param value
934    *    The new value for this property.
935    *    <br>Can be <jk>null</jk> to unset the property.
936    * @return This object.
937    */
938   public SchemaInfo setMinimum(Number value) {
939      minimum = value;
940      return this;
941   }
942
943   /**
944    * Bean property setter:  <property>minItems</property>.
945    *
946    * @param value
947    *    The new value for this property.
948    *    <br>Can be <jk>null</jk> to unset the property.
949    * @return This object.
950    */
951   public SchemaInfo setMinItems(Integer value) {
952      minItems = value;
953      return this;
954   }
955
956   /**
957    * Bean property setter:  <property>minLength</property>.
958    *
959    * @param value
960    *    The new value for this property.
961    *    <br>Can be <jk>null</jk> to unset the property.
962    * @return This object.
963    */
964   public SchemaInfo setMinLength(Integer value) {
965      minLength = value;
966      return this;
967   }
968
969   /**
970    * Bean property setter:  <property>minProperties</property>.
971    *
972    * @param value
973    *    The new value for this property.
974    *    <br>Can be <jk>null</jk> to unset the property.
975    * @return This object.
976    */
977   public SchemaInfo setMinProperties(Integer value) {
978      minProperties = value;
979      return this;
980   }
981
982   /**
983    * Bean property setter:  <property>multipleOf</property>.
984    *
985    * @param value
986    *    The new value for this property.
987    *    <br>Can be <jk>null</jk> to unset the property.
988    * @return This object.
989    */
990   public SchemaInfo setMultipleOf(Number value) {
991      multipleOf = value;
992      return this;
993   }
994
995   /**
996    * Bean property setter:  <property>pattern</property>.
997    *
998    * @param value
999    *    The new value for this property.
1000    *    <br>This string SHOULD be a valid regular expression.
1001    *    <br>Can be <jk>null</jk> to unset the property.
1002    * @return This object.
1003    */
1004   public SchemaInfo setPattern(String value) {
1005      pattern = value;
1006      return this;
1007   }
1008
1009   /**
1010    * Bean property setter:  <property>properties</property>.
1011    *
1012    * @param value
1013    *    The new value for this property.
1014    *    <br>Can be <jk>null</jk> to unset the property.
1015    * @return This object.
1016    */
1017   public SchemaInfo setProperties(Map<String,SchemaInfo> value) {
1018      properties.clear();
1019      if (nn(value))
1020         properties.putAll(value);
1021      return this;
1022   }
1023
1024   /**
1025    * Bean property setter:  <property>readOnly</property>.
1026    *
1027    * @param value
1028    *    The new value for this property.
1029    *    <br>Can be <jk>null</jk> to unset the property.
1030    * @return This object.
1031    */
1032   public SchemaInfo setReadOnly(Boolean value) {
1033      readOnly = value;
1034      return this;
1035   }
1036
1037   /**
1038    * Bean property setter:  <property>$ref</property>.
1039    *
1040    * @param value
1041    *    The new value for this property.
1042    *    <br>Can be <jk>null</jk> to unset the property.
1043    * @return This object.
1044    */
1045   @Beanp("$ref")
1046   public SchemaInfo setRef(String value) {
1047      ref = value;
1048      return this;
1049   }
1050
1051   /**
1052    * Bean property setter:  <property>required</property>.
1053    *
1054    * @param value
1055    *    The new value for this property.
1056    *    <br>Can be <jk>null</jk> to unset the property.
1057    * @return This object.
1058    */
1059   public SchemaInfo setRequired(Boolean value) {
1060      required = value;
1061      return this;
1062   }
1063
1064   /**
1065    * Bean property setter:  <property>requiredProperties</property>.
1066    *
1067    * <p>
1068    * The list of required properties.
1069    *
1070    * @param value
1071    *    The new value for this property.
1072    *    <br>Valid values:
1073    *    <ul>
1074    *       <li><js>"http"</js>
1075    *       <li><js>"https"</js>
1076    *       <li><js>"ws"</js>
1077    *       <li><js>"wss"</js>
1078    *    </ul>
1079    *    <br>Can be <jk>null</jk> to unset the property.
1080    * @return This object.
1081    */
1082   public SchemaInfo setRequiredProperties(Collection<String> value) {
1083      requiredProperties.clear();
1084      if (nn(value))
1085         requiredProperties.addAll(value);
1086      return this;
1087   }
1088
1089   /**
1090    * Bean property fluent setter:  <property>requiredProperties</property>.
1091    *
1092    * @param value
1093    *    The new value for this property.
1094    * @return This object.
1095    */
1096   public SchemaInfo setRequiredProperties(String...value) {
1097      setRequiredProperties(setb(String.class).sparse().addAny((Object[])value).build());
1098      return this;
1099   }
1100
1101   /**
1102    * Bean property setter:  <property>title</property>.
1103    *
1104    * @param value
1105    *    The new value for this property.
1106    *    <br>Can be <jk>null</jk> to unset the property.
1107    * @return This object.
1108    */
1109   public SchemaInfo setTitle(String value) {
1110      title = value;
1111      return this;
1112   }
1113
1114   /**
1115    * Bean property setter:  <property>type</property>.
1116    *
1117    * @param value
1118    *    The new value for this property.
1119    *    <br>Can be <jk>null</jk> to unset the property.
1120    *    <br>Possible values include:
1121    *    <ul>
1122    *       <li><js>"object"</js>
1123    *       <li><js>"string"</js>
1124    *       <li><js>"number"</js>
1125    *       <li><js>"integer"</js>
1126    *       <li><js>"boolean"</js>
1127    *       <li><js>"array"</js>
1128    *       <li><js>"file"</js>
1129    *    </ul>
1130    * @return This object.
1131    */
1132   public SchemaInfo setType(String value) {
1133      type = value;
1134      return this;
1135   }
1136
1137   /**
1138    * Bean property setter:  <property>uniqueItems</property>.
1139    *
1140    * @param value
1141    *    The new value for this property.
1142    *    <br>Can be <jk>null</jk> to unset the property.
1143    * @return This object.
1144    */
1145   public SchemaInfo setUniqueItems(Boolean value) {
1146      uniqueItems = value;
1147      return this;
1148   }
1149
1150   /**
1151    * Bean property setter:  <property>xml</property>.
1152    *
1153    * @param value
1154    *    The new value for this property.
1155    *    <br>Can be <jk>null</jk> to unset the property.
1156    * @return This object.
1157    */
1158   public SchemaInfo setXml(Xml value) {
1159      xml = value;
1160      return this;
1161   }
1162
1163   /**
1164    * Sets strict mode on this bean.
1165    *
1166    * @return This object.
1167    */
1168   @Override
1169   public SchemaInfo strict() {
1170      super.strict();
1171      return this;
1172   }
1173
1174   /**
1175    * Sets strict mode on this bean.
1176    *
1177    * @param value
1178    *    The new value for this property.
1179    *    <br>Non-boolean values will be converted to boolean using <code>Boolean.<jsm>valueOf</jsm>(value.toString())</code>.
1180    *    <br>Can be <jk>null</jk> (interpreted as <jk>false</jk>).
1181    * @return This object.
1182    */
1183   @Override
1184   public SchemaInfo strict(Object value) {
1185      super.strict(value);
1186      return this;
1187   }
1188}