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