1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.juneau.bean.openapi3;
18
19 import static org.apache.juneau.commons.utils.AssertionUtils.*;
20 import static org.apache.juneau.commons.utils.CollectionUtils.*;
21 import static org.apache.juneau.commons.utils.Utils.*;
22 import static org.apache.juneau.internal.ConverterUtils.*;
23
24 import java.util.*;
25
26 import org.apache.juneau.annotation.*;
27 import org.apache.juneau.commons.collections.*;
28
29 /**
30 * Allows the definition of input and output data types.
31 *
32 * <p>
33 * The Schema Object allows the definition of input and output data types, including objects, primitives, and arrays.
34 * This object is an extended subset of the JSON Schema Specification Draft 4, with additional extensions provided
35 * by the OpenAPI Specification to allow for more complete documentation.
36 *
37 * <h5 class='section'>OpenAPI Specification:</h5>
38 * <p>
39 * The Schema Object supports all properties from JSON Schema Draft 4, including but not limited to:
40 * <ul class='spaced-list'>
41 * <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>
42 * <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>)
43 * <li><c>title</c> (string) - A short title for the schema
44 * <li><c>description</c> (string) - A description of the schema (CommonMark syntax may be used)
45 * <li><c>default</c> (any) - The default value
46 * <li><c>multipleOf</c> (number) - Must be a multiple of this value
47 * <li><c>maximum</c> (number) - Maximum value (inclusive by default)
48 * <li><c>exclusiveMaximum</c> (boolean) - If true, maximum is exclusive
49 * <li><c>minimum</c> (number) - Minimum value (inclusive by default)
50 * <li><c>exclusiveMinimum</c> (boolean) - If true, minimum is exclusive
51 * <li><c>maxLength</c> (integer) - Maximum string length
52 * <li><c>minLength</c> (integer) - Minimum string length
53 * <li><c>pattern</c> (string) - Regular expression pattern the string must match
54 * <li><c>maxItems</c> (integer) - Maximum array length
55 * <li><c>minItems</c> (integer) - Minimum array length
56 * <li><c>uniqueItems</c> (boolean) - If true, array items must be unique
57 * <li><c>maxProperties</c> (integer) - Maximum number of object properties
58 * <li><c>minProperties</c> (integer) - Minimum number of object properties
59 * <li><c>required</c> (array of string) - Required property names
60 * <li><c>enum</c> (array) - Possible values for this schema
61 * <li><c>properties</c> (map of {@link SchemaInfo}) - Object property definitions
62 * <li><c>items</c> ({@link Items}) - Schema for array items
63 * <li><c>allOf</c> (array of {@link SchemaInfo}) - Must validate against all schemas
64 * <li><c>oneOf</c> (array of {@link SchemaInfo}) - Must validate against exactly one schema
65 * <li><c>anyOf</c> (array of {@link SchemaInfo}) - Must validate against any schema
66 * <li><c>not</c> ({@link SchemaInfo}) - Must not validate against this schema
67 * <li><c>nullable</c> (boolean) - Allows the value to be null (OpenAPI 3.0 extension)
68 * <li><c>discriminator</c> ({@link Discriminator}) - Discriminator for polymorphism (OpenAPI extension)
69 * <li><c>readOnly</c> (boolean) - Relevant only for Schema properties (OpenAPI extension)
70 * <li><c>writeOnly</c> (boolean) - Relevant only for Schema properties (OpenAPI extension)
71 * <li><c>xml</c> ({@link Xml}) - XML representation details (OpenAPI extension)
72 * <li><c>externalDocs</c> ({@link ExternalDocumentation}) - Additional external documentation (OpenAPI extension)
73 * <li><c>example</c> (any) - Example value (OpenAPI extension)
74 * <li><c>deprecated</c> (boolean) - Specifies that the schema is deprecated (OpenAPI extension)
75 * </ul>
76 *
77 * <h5 class='section'>Example:</h5>
78 * <p class='bjava'>
79 * <jc>// Create a schema for a Pet object</jc>
80 * SchemaInfo <jv>schema</jv> = <jk>new</jk> SchemaInfo()
81 * .setType(<js>"object"</js>)
82 * .setRequired(<js>"id"</js>, <js>"name"</js>)
83 * .setProperties(
84 * JsonMap.<jsm>of</jsm>(
85 * <js>"id"</js>, <jk>new</jk> SchemaInfo().setType(<js>"integer"</js>).setFormat(<js>"int64"</js>),
86 * <js>"name"</js>, <jk>new</jk> SchemaInfo().setType(<js>"string"</js>),
87 * <js>"tag"</js>, <jk>new</jk> SchemaInfo().setType(<js>"string"</js>)
88 * )
89 * );
90 * </p>
91 *
92 * <h5 class='section'>See Also:</h5><ul>
93 * <li class='link'><a class="doclink" href="https://spec.openapis.org/oas/v3.0.0#schema-object">OpenAPI Specification > Schema Object</a>
94 * <li class='link'><a class="doclink" href="https://swagger.io/docs/specification/data-models/">OpenAPI Data Models</a>
95 * <li class='link'><a class="doclink" href="https://json-schema.org/">JSON Schema Specification</a>
96 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanOpenApi3">juneau-bean-openapi-v3</a>
97 * </ul>
98 */
99 public class SchemaInfo extends OpenApiElement {
100
101 private String format, title, description, pattern, ref, type;
102 private Number multipleOf, maximum, minimum;
103 private Integer maxLength, minLength, maxItems, minItems, maxProperties, minProperties;
104 private Boolean exclusiveMaximum, exclusiveMinimum, uniqueItems, nullable, writeOnly, readOnly, deprecated;
105 private Object default_,
106 example;
107 private Items items;
108 private Xml xml;
109 private ExternalDocumentation externalDocs;
110 private List<Object> allOf = list(), oneOf = list(), anyOf = list(), enum_ = list();
111 private List<String> required = list();
112 private Discriminator discriminator;
113 private Map<String,SchemaInfo> properties;
114 private SchemaInfo additionalProperties;
115 private SchemaInfo not;
116
117 /**
118 * Default constructor.
119 */
120 public SchemaInfo() {}
121
122 /**
123 * Copy constructor.
124 *
125 * @param copyFrom The object to copy.
126 */
127 public SchemaInfo(SchemaInfo copyFrom) {
128 super(copyFrom);
129
130 this.format = copyFrom.format;
131 this.title = copyFrom.title;
132 this.description = copyFrom.description;
133 this.ref = copyFrom.ref;
134 this.nullable = copyFrom.nullable;
135 this.writeOnly = copyFrom.writeOnly;
136 this.deprecated = copyFrom.deprecated;
137 this.pattern = copyFrom.pattern;
138 this.type = copyFrom.type;
139 this.discriminator = copyFrom.discriminator;
140 this.multipleOf = copyFrom.multipleOf;
141 this.maximum = copyFrom.maximum;
142 this.minimum = copyFrom.minimum;
143 this.maxLength = copyFrom.maxLength;
144 this.minLength = copyFrom.minLength;
145 this.maxItems = copyFrom.maxItems;
146 this.minItems = copyFrom.minItems;
147 this.maxProperties = copyFrom.maxProperties;
148 this.minProperties = copyFrom.minProperties;
149 this.exclusiveMaximum = copyFrom.exclusiveMaximum;
150 this.exclusiveMinimum = copyFrom.exclusiveMinimum;
151 this.uniqueItems = copyFrom.uniqueItems;
152 this.readOnly = copyFrom.readOnly;
153 this.default_ = copyFrom.default_;
154 this.example = copyFrom.example;
155 this.items = copyFrom.items == null ? null : copyFrom.items.copy();
156 this.xml = copyFrom.xml == null ? null : copyFrom.xml.copy();
157 this.externalDocs = copyFrom.externalDocs == null ? null : copyFrom.externalDocs.copy();
158 if (nn(copyFrom.enum_))
159 enum_.addAll(copyFrom.enum_);
160 if (nn(copyFrom.allOf))
161 allOf.addAll(copyFrom.allOf);
162 if (nn(copyFrom.required))
163 required.addAll(copyFrom.required);
164 if (nn(copyFrom.anyOf))
165 anyOf.addAll(copyFrom.anyOf);
166 if (nn(copyFrom.oneOf))
167 oneOf.addAll(copyFrom.oneOf);
168 this.properties = copyOf(copyFrom.properties, SchemaInfo::copy);
169 this.additionalProperties = copyFrom.additionalProperties == null ? null : copyFrom.additionalProperties.copy();
170 this.not = copyFrom.not == null ? null : copyFrom.not.copy();
171 }
172
173 /**
174 * Adds one or more values to the <property>allOf</property> property.
175 *
176 * @param values
177 * The values to add to this property.
178 * <br>Valid types:
179 * <ul>
180 * <li><code>Object</code>
181 * <li><code>Collection<Object></code>
182 * <li><code>String</code> - JSON array representation of <code>Collection<Object></code>
183 * <h5 class='figure'>Example:</h5>
184 * <p class='bcode'>
185 * allOf(<js>"['foo','bar']"</js>);
186 * </p>
187 * <li><code>String</code> - Individual values
188 * <h5 class='figure'>Example:</h5>
189 * <p class='bcode'>
190 * allOf(<js>"foo"</js>, <js>"bar"</js>);
191 * </p>
192 * </ul>
193 * <br>Ignored if <jk>null</jk>.
194 * @return This object
195 */
196 public SchemaInfo addAllOf(Object...values) {
197 if (nn(values))
198 for (var v : values)
199 if (nn(v))
200 allOf.add(v);
201 return this;
202 }
203
204 /**
205 * Adds one or more values to the <property>allOf</property> property.
206 *
207 * @param values
208 * The values to add to this property.
209 * <br>Valid types:
210 * <ul>
211 * <li><code>Object</code>
212 * <li><code>Collection<Object></code>
213 * <li><code>String</code> - JSON array representation of <code>Collection<Object></code>
214 * <h5 class='figure'>Example:</h5>
215 * <p class='bcode'>
216 * allOf(<js>"['foo','bar']"</js>);
217 * </p>
218 * <li><code>String</code> - Individual values
219 * <h5 class='figure'>Example:</h5>
220 * <p class='bcode'>
221 * allOf(<js>"foo"</js>, <js>"bar"</js>);
222 * </p>
223 * </ul>
224 * <br>Ignored if <jk>null</jk>.
225 * @return This object
226 */
227 public SchemaInfo addAnyOf(Object...values) {
228 if (nn(values))
229 for (var v : values)
230 if (nn(v))
231 anyOf.add(v);
232 return this;
233 }
234
235 /**
236 * Adds one or more values to the <property>enum</property> property.
237 *
238 * @param values
239 * The values to add to this property.
240 * <br>Valid types:
241 * <ul>
242 * <li><code>Object</code>
243 * <li><code>Collection<Object></code>
244 * <li><code>String</code> - JSON array representation of <code>Collection<Object></code>
245 * <h5 class='figure'>Example:</h5>
246 * <p class='bcode'>
247 * enum_(<js>"['foo','bar']"</js>);
248 * </p>
249 * <li><code>String</code> - Individual values
250 * <h5 class='figure'>Example:</h5>
251 * <p class='bcode'>
252 * enum_(<js>"foo"</js>, <js>"bar"</js>);
253 * </p>
254 * </ul>
255 * <br>Ignored if <jk>null</jk>.
256 * @return This object
257 */
258 public SchemaInfo addEnum(Object...values) {
259 if (nn(values))
260 for (var v : values)
261 if (nn(v))
262 enum_.add(v);
263 return this;
264 }
265
266 /**
267 * Adds one or more values to the <property>allOf</property> property.
268 *
269 * @param values
270 * The values to add to this property.
271 * <br>Valid types:
272 * <ul>
273 * <li><code>Object</code>
274 * <li><code>Collection<Object></code>
275 * <li><code>String</code> - JSON array representation of <code>Collection<Object></code>
276 * <h5 class='figure'>Example:</h5>
277 * <p class='bcode'>
278 * allOf(<js>"['foo','bar']"</js>);
279 * </p>
280 * <li><code>String</code> - Individual values
281 * <h5 class='figure'>Example:</h5>
282 * <p class='bcode'>
283 * allOf(<js>"foo"</js>, <js>"bar"</js>);
284 * </p>
285 * </ul>
286 * <br>Ignored if <jk>null</jk>.
287 * @return This object
288 */
289 public SchemaInfo addOneOf(Object...values) {
290 if (nn(values))
291 for (var v : values)
292 if (nn(v))
293 oneOf.add(v);
294 return this;
295 }
296
297 /**
298 * Same as {@link #addRequired(String...)}.
299 *
300 * @param values
301 * The new value for this property.
302 * <br>Valid types:
303 * <ul>
304 * <li><code>Collection<String></code>
305 * <li><code>String</code> - JSON array representation of <code>Collection<String></code>
306 * <h5 class='figure'>Example:</h5>
307 * <p class='bcode'>
308 * schemes(<js>"['scheme1','scheme2']"</js>);
309 * </p>
310 * <li><code>String</code> - Individual values
311 * <h5 class='figure'>Example:</h5>
312 * <p class='bcode'>
313 * schemes(<js>"scheme1</js>, <js>"scheme2"</js>);
314 * </p>
315 * </ul>
316 * @return This object
317 */
318 public SchemaInfo addRequired(String...values) {
319 if (nn(values))
320 for (var v : values)
321 if (nn(v))
322 required.add(v);
323 return this;
324 }
325
326 /**
327 * Make a deep copy of this object.
328 *
329 * @return A deep copy of this object.
330 */
331 public SchemaInfo copy() {
332 return new SchemaInfo(this);
333 }
334
335 @Override /* Overridden from SwaggerElement */
336 public <T> T get(String property, Class<T> type) {
337 assertArgNotNull("property", property);
338 return switch (property) { // NOSONAR
339 case "format" -> toType(getFormat(), type);
340 case "title" -> toType(getTitle(), type);
341 case "description" -> toType(getDescription(), type);
342 case "default" -> toType(getDefault(), type);
343 case "multipleOf" -> toType(getMultipleOf(), type);
344 case "maximum" -> toType(getMaximum(), type);
345 case "exclusiveMaximum" -> toType(getExclusiveMaximum(), type);
346 case "minimum" -> toType(getMinimum(), type);
347 case "exclusiveMinimum" -> toType(getExclusiveMinimum(), type);
348 case "maxLength" -> toType(getMaxLength(), type);
349 case "minLength" -> toType(getMinLength(), type);
350 case "pattern" -> toType(getPattern(), type);
351 case "maxItems" -> toType(getMaxItems(), type);
352 case "minItems" -> toType(getMinItems(), type);
353 case "uniqueItems" -> toType(getUniqueItems(), type);
354 case "maxProperties" -> toType(getMaxProperties(), type);
355 case "minProperties" -> toType(getMinProperties(), type);
356 case "required" -> toType(getRequired(), type);
357 case "enum" -> toType(getEnum(), type);
358 case "type" -> toType(getType(), type);
359 case "items" -> toType(getItems(), type);
360 case "allOf" -> toType(getAllOf(), type);
361 case "oneOf" -> toType(getOneOf(), type);
362 case "anyOf" -> toType(getAnyOf(), type);
363 case "properties" -> toType(getProperties(), type);
364 case "additionalProperties" -> toType(getAdditionalProperties(), type);
365 case "not" -> toType(getNot(), type);
366 case "nullable" -> toType(getNullable(), type);
367 case "deprecated" -> toType(getDeprecated(), type);
368 case "discriminator" -> toType(getDiscriminator(), type);
369 case "readOnly" -> toType(getReadOnly(), type);
370 case "writeOnly" -> toType(getWriteOnly(), type);
371 case "xml" -> toType(getXml(), type);
372 case "externalDocs" -> toType(getExternalDocs(), type);
373 case "example" -> toType(getExample(), type);
374 case "$ref" -> toType(getRef(), type);
375 default -> super.get(property, type);
376 };
377 }
378
379 /**
380 * Bean property getter: <property>additionalProperties</property>.
381 *
382 * @return The property value, or <jk>null</jk> if it is not set.
383 */
384 public SchemaInfo getAdditionalProperties() { return additionalProperties; }
385
386 /**
387 * Bean property getter: <property>allOf</property>.
388 *
389 * @return The property value, or <jk>null</jk> if it is not set.
390 */
391 public List<Object> getAllOf() { return nullIfEmpty(allOf); }
392
393 /**
394 * Bean property getter: <property>allOf</property>.
395 *
396 * @return The property value, or <jk>null</jk> if it is not set.
397 */
398 public List<Object> getAnyOf() { return nullIfEmpty(anyOf); }
399
400 /**
401 * Bean property getter: <property>default</property>.
402 *
403 * <p>
404 * Unlike JSON Schema, the value MUST conform to the defined type for the Schema Object.
405 *
406 * @return The property value, or <jk>null</jk> if it is not set.
407 */
408 public Object getDefault() { return default_; }
409
410 /**
411 * Bean property getter: <property>deprecated</property>.
412 *
413 * @return The property value, or <jk>null</jk> if it is not set.
414 */
415 public Boolean getDeprecated() { return deprecated; }
416
417 /**
418 * Bean property getter: <property>description</property>.
419 *
420 * @return The property value, or <jk>null</jk> if it is not set.
421 */
422 public String getDescription() { return description; }
423
424 /**
425 * Bean property getter: <property>discriminator</property>.
426 *
427 * @return The property value, or <jk>null</jk> if it is not set.
428 */
429 public Discriminator getDiscriminator() { return discriminator; }
430
431 /**
432 * Bean property getter: <property>enum</property>.
433 *
434 * @return The property value, or <jk>null</jk> if it is not set.
435 */
436 public List<Object> getEnum() { return nullIfEmpty(enum_); }
437
438 /**
439 * Bean property getter: <property>example</property>.
440 *
441 * @return The property value, or <jk>null</jk> if it is not set.
442 */
443 public Object getExample() { return example; }
444
445 /**
446 * Bean property getter: <property>exclusiveMaximum</property>.
447 *
448 * @return The property value, or <jk>null</jk> if it is not set.
449 */
450 public Boolean getExclusiveMaximum() { return exclusiveMaximum; }
451
452 /**
453 * Bean property getter: <property>exclusiveMinimum</property>.
454 *
455 * @return The property value, or <jk>null</jk> if it is not set.
456 */
457 public Boolean getExclusiveMinimum() { return exclusiveMinimum; }
458
459 /**
460 * Bean property getter: <property>externalDocs</property>.
461 *
462 * @return The property value, or <jk>null</jk> if it is not set.
463 */
464 public ExternalDocumentation getExternalDocs() { return externalDocs; }
465
466 /**
467 * Bean property getter: <property>format</property>.
468 *
469 * @return The property value, or <jk>null</jk> if it is not set.
470 */
471 public String getFormat() { return format; }
472
473 /**
474 * Bean property getter: <property>items</property>.
475 *
476 * @return The property value, or <jk>null</jk> if it is not set.
477 */
478 public Items getItems() { return items; }
479
480 /**
481 * Bean property getter: <property>maximum</property>.
482 *
483 * @return The property value, or <jk>null</jk> if it is not set.
484 */
485 public Number getMaximum() { return maximum; }
486
487 /**
488 * Bean property getter: <property>maxItems</property>.
489 *
490 * @return The property value, or <jk>null</jk> if it is not set.
491 */
492 public Integer getMaxItems() { return maxItems; }
493
494 /**
495 * Bean property getter: <property>maxLength</property>.
496 *
497 * @return The property value, or <jk>null</jk> if it is not set.
498 */
499 public Integer getMaxLength() { return maxLength; }
500
501 /**
502 * Bean property getter: <property>maxProperties</property>.
503 *
504 * @return The property value, or <jk>null</jk> if it is not set.
505 */
506 public Integer getMaxProperties() { return maxProperties; }
507
508 /**
509 * Bean property getter: <property>minimum</property>.
510 *
511 * @return The property value, or <jk>null</jk> if it is not set.
512 */
513 public Number getMinimum() { return minimum; }
514
515 /**
516 * Bean property getter: <property>minItems</property>.
517 *
518 * @return The property value, or <jk>null</jk> if it is not set.
519 */
520 public Integer getMinItems() { return minItems; }
521
522 /**
523 * Bean property getter: <property>minLength</property>.
524 *
525 * @return The property value, or <jk>null</jk> if it is not set.
526 */
527 public Integer getMinLength() { return minLength; }
528
529 /**
530 * Bean property getter: <property>minProperties</property>.
531 *
532 * @return The property value, or <jk>null</jk> if it is not set.
533 */
534 public Integer getMinProperties() { return minProperties; }
535
536 /**
537 * Bean property getter: <property>multipleOf</property>.
538 *
539 * @return The property value, or <jk>null</jk> if it is not set.
540 */
541 public Number getMultipleOf() { return multipleOf; }
542
543 /**
544 * Bean property getter: <property>not</property>.
545 *
546 * @return The property value, or <jk>null</jk> if it is not set.
547 */
548 public SchemaInfo getNot() { return not; }
549
550 /**
551 * Bean property getter: <property>uniqueItems</property>.
552 *
553 * @return The property value, or <jk>null</jk> if it is not set.
554 */
555 public Boolean getNullable() { return nullable; }
556
557 /**
558 * Bean property getter: <property>allOf</property>.
559 *
560 * @return The property value, or <jk>null</jk> if it is not set.
561 */
562 public List<Object> getOneOf() { return nullIfEmpty(oneOf); }
563
564 /**
565 * Bean property getter: <property>pattern</property>.
566 *
567 * @return The property value, or <jk>null</jk> if it is not set.
568 */
569 public String getPattern() { return pattern; }
570
571 /**
572 * Bean property getter: <property>properties</property>.
573 *
574 * @return The property value, or <jk>null</jk> if it is not set.
575 */
576 public Map<String,SchemaInfo> getProperties() { return properties; }
577
578 /**
579 * Bean property getter: <property>readOnly</property>.
580 *
581 * @return The property value, or <jk>null</jk> if it is not set.
582 */
583 public Boolean getReadOnly() { return readOnly; }
584
585 /**
586 * Bean property getter: <property>$ref</property>.
587 *
588 * @return The property value, or <jk>null</jk> if it is not set.
589 */
590 @Beanp("$ref")
591 public String getRef() { return ref; }
592
593 /**
594 * Bean property getter: <property>required</property>.
595 *
596 * <p>
597 * The list of required properties.
598 *
599 * @return The property value, or <jk>null</jk> if it is not set.
600 */
601 public List<String> getRequired() { return nullIfEmpty(required); }
602
603 /**
604 * Bean property getter: <property>title</property>.
605 *
606 * @return The property value, or <jk>null</jk> if it is not set.
607 */
608 public String getTitle() { return title; }
609
610 /**
611 * Bean property getter: <property>type</property>.
612 *
613 * @return The property value, or <jk>null</jk> if it is not set.
614 */
615 public String getType() { return type; }
616
617 /**
618 * Bean property getter: <property>uniqueItems</property>.
619 *
620 * @return The property value, or <jk>null</jk> if it is not set.
621 */
622 public Boolean getUniqueItems() { return uniqueItems; }
623
624 /**
625 * Bean property getter: <property>WriteOnly</property>.
626 *
627 * @return The property value, or <jk>null</jk> if it is not set.
628 */
629 public Boolean getWriteOnly() { return writeOnly; }
630
631 /**
632 * Bean property getter: <property>xml</property>.
633 *
634 * @return The property value, or <jk>null</jk> if it is not set.
635 */
636 public Xml getXml() { return xml; }
637
638 @Override /* Overridden from SwaggerElement */
639 public Set<String> keySet() {
640 // @formatter:off
641 var s = setb(String.class)
642 .addIf(nn(ref), "$ref")
643 .addIf(nn(additionalProperties), "additionalProperties")
644 .addIf(ne(allOf), "allOf")
645 .addIf(ne(anyOf), "anyOf")
646 .addIf(nn(default_), "default")
647 .addIf(nn(deprecated), "deprecated")
648 .addIf(nn(description), "description")
649 .addIf(nn(discriminator), "discriminator")
650 .addIf(ne(enum_), "enum")
651 .addIf(nn(example), "example")
652 .addIf(nn(exclusiveMaximum), "exclusiveMaximum")
653 .addIf(nn(exclusiveMinimum), "exclusiveMinimum")
654 .addIf(nn(externalDocs), "externalDocs")
655 .addIf(nn(format), "format")
656 .addIf(nn(items), "items")
657 .addIf(nn(maxItems), "maxItems")
658 .addIf(nn(maxLength), "maxLength")
659 .addIf(nn(maxProperties), "maxProperties")
660 .addIf(nn(maximum), "maximum")
661 .addIf(nn(minItems), "minItems")
662 .addIf(nn(minLength), "minLength")
663 .addIf(nn(minProperties), "minProperties")
664 .addIf(nn(minimum), "minimum")
665 .addIf(nn(multipleOf), "multipleOf")
666 .addIf(nn(not), "not")
667 .addIf(nn(nullable), "nullable")
668 .addIf(ne(oneOf), "oneOf")
669 .addIf(nn(pattern), "pattern")
670 .addIf(nn(properties), "properties")
671 .addIf(nn(readOnly), "readOnly")
672 .addIf(ne(required), "required")
673 .addIf(nn(title), "title")
674 .addIf(nn(type), "type")
675 .addIf(nn(uniqueItems), "uniqueItems")
676 .addIf(nn(writeOnly), "writeOnly")
677 .addIf(nn(xml), "xml")
678 .build();
679 // @formatter:on
680 return new MultiSet<>(s, super.keySet());
681 }
682
683 /**
684 * Resolves any <js>"$ref"</js> attributes in this element.
685 *
686 * @param openApi The swagger document containing the definitions.
687 * @param refStack Keeps track of previously-visited references so that we don't cause recursive loops.
688 * @param maxDepth
689 * The maximum depth to resolve references.
690 * <br>After that level is reached, <code>$ref</code> references will be left alone.
691 * <br>Useful if you have very complex models and you don't want your swagger page to be overly-complex.
692 * @return
693 * This object with references resolved.
694 * <br>May or may not be the same object.
695 */
696 public SchemaInfo resolveRefs(OpenApi openApi, Deque<String> refStack, int maxDepth) {
697
698 if (nn(ref)) {
699 if (refStack.contains(ref) || refStack.size() >= maxDepth)
700 return this;
701 refStack.addLast(ref);
702 var r = openApi.findRef(ref, SchemaInfo.class);
703 r = r.resolveRefs(openApi, refStack, maxDepth);
704 refStack.removeLast();
705 return r;
706 }
707
708 if (nn(items))
709 items = items.resolveRefs(openApi, refStack, maxDepth);
710
711 if (nn(properties))
712 for (var e : properties.entrySet())
713 e.setValue(e.getValue().resolveRefs(openApi, refStack, maxDepth));
714
715 if (nn(additionalProperties))
716 additionalProperties = additionalProperties.resolveRefs(openApi, refStack, maxDepth);
717
718 this.example = null;
719
720 return this;
721 }
722
723 @Override /* Overridden from SwaggerElement */
724 public SchemaInfo set(String property, Object value) {
725 assertArgNotNull("property", property);
726 return switch (property) { // NOSONAR
727 case "$ref" -> setRef(value);
728 case "additionalProperties" -> setAdditionalProperties(toType(value, SchemaInfo.class));
729 case "allOf" -> setAllOf(listb(Object.class).addAny(value).sparse().build());
730 case "anyOf" -> setAnyOf(listb(Object.class).addAny(value).sparse().build());
731 case "default" -> setDefault(value);
732 case "deprecated" -> setDeprecated(toBoolean(value));
733 case "description" -> setDescription(s(value));
734 case "discriminator" -> setDiscriminator(toType(value, Discriminator.class));
735 case "enum" -> setEnum(listb(Object.class).addAny(value).sparse().build());
736 case "example" -> setExample(value);
737 case "exclusiveMaximum" -> setExclusiveMaximum(toBoolean(value));
738 case "exclusiveMinimum" -> setExclusiveMinimum(toBoolean(value));
739 case "externalDocs" -> setExternalDocs(toType(value, ExternalDocumentation.class));
740 case "format" -> setFormat(s(value));
741 case "items" -> setItems(toType(value, Items.class));
742 case "maxItems" -> setMaxItems(toInteger(value));
743 case "maxLength" -> setMaxLength(toInteger(value));
744 case "maxProperties" -> setMaxProperties(toInteger(value));
745 case "maximum" -> setMaximum(toNumber(value));
746 case "minItems" -> setMinItems(toInteger(value));
747 case "minLength" -> setMinLength(toInteger(value));
748 case "minProperties" -> setMinProperties(toInteger(value));
749 case "minimum" -> setMinimum(toNumber(value));
750 case "multipleOf" -> setMultipleOf(toNumber(value));
751 case "not" -> setNot(toType(value, SchemaInfo.class));
752 case "nullable" -> setNullable(toBoolean(value));
753 case "oneOf" -> setOneOf(listb(Object.class).addAny(value).sparse().build());
754 case "pattern" -> setPattern(s(value));
755 case "properties" -> setProperties(toMapBuilder(value, String.class, SchemaInfo.class).sparse().build());
756 case "readOnly" -> setReadOnly(toBoolean(value));
757 case "required" -> setRequired(listb(String.class).addAny(value).sparse().build());
758 case "title" -> setTitle(s(value));
759 case "type" -> setType(s(value));
760 case "uniqueItems" -> setUniqueItems(toBoolean(value));
761 case "writeOnly" -> setWriteOnly(toBoolean(value));
762 case "xml" -> setXml(toType(value, Xml.class));
763 default -> {
764 super.set(property, value);
765 yield this;
766 }
767 };
768 }
769
770 /**
771 * Bean property setter: <property>additionalProperties</property>.
772 *
773 * @param value
774 * The new value for this property.
775 * <br>Can be <jk>null</jk> to unset the property.
776 * @return This object
777 */
778 public SchemaInfo setAdditionalProperties(SchemaInfo value) {
779 additionalProperties = value;
780 return this;
781 }
782
783 /**
784 * Bean property setter: <property>allOf</property>.
785 *
786 * @param value
787 * The new value for this property.
788 * <br>Can be <jk>null</jk> to unset the property.
789 * @return This object
790 */
791 public SchemaInfo setAllOf(Collection<Object> value) {
792 allOf.clear();
793 if (nn(value))
794 allOf.addAll(value);
795 return this;
796 }
797
798 /**
799 * Bean property setter: <property>allOf</property>.
800 *
801 * @param value
802 * The new value for this property.
803 * <br>Can be <jk>null</jk> to unset the property.
804 * @return This object
805 */
806 public SchemaInfo setAnyOf(Collection<Object> value) {
807 anyOf.clear();
808 if (nn(value))
809 anyOf.addAll(value);
810 return this;
811 }
812
813 /**
814 * Bean property setter: <property>default</property>.
815 *
816 * <p>
817 * Unlike JSON Schema, the value MUST conform to the defined type for the Schema Object.
818 *
819 * @param value
820 * The new value for this property.
821 * <br>Can be <jk>null</jk> to unset the property.
822 * @return This object
823 */
824 public SchemaInfo setDefault(Object value) {
825 default_ = value;
826 return this;
827 }
828
829 /**
830 * Bean property setter: <property>deprecated</property>.
831 *
832 * @param value
833 * The new value for this property.
834 * <br>Can be <jk>null</jk> to unset the property.
835 * @return This object
836 */
837 public SchemaInfo setDeprecated(Boolean value) {
838 deprecated = value;
839 return this;
840 }
841
842 /**
843 * Bean property setter: <property>description</property>.
844 *
845 * @param value
846 * The new value for this property.
847 * <br>Can be <jk>null</jk> to unset the property.
848 * @return This object
849 */
850 public SchemaInfo setDescription(String value) {
851 description = value;
852 return this;
853 }
854
855 /**
856 * Bean property setter: <property>discriminator</property>.
857 *
858 * @param value
859 * The new value for this property.
860 * <br>Can be <jk>null</jk> to unset the property.
861 * @return This object
862 */
863 public SchemaInfo setDiscriminator(Discriminator value) {
864 discriminator = value;
865 return this;
866 }
867
868 /**
869 * Bean property setter: <property>enum</property>.
870 *
871 * @param value
872 * The new value for this property.
873 * <br>Can be <jk>null</jk> to unset the property.
874 * @return This object
875 */
876 public SchemaInfo setEnum(Collection<Object> value) {
877 enum_.clear();
878 if (nn(value))
879 enum_.addAll(value);
880 return this;
881 }
882
883 /**
884 * Bean property setter: <property>example</property>.
885 *
886 * @param value
887 * The new value for this property.
888 * <br>Can be <jk>null</jk> to unset the property.
889 * @return This object
890 */
891 public SchemaInfo setExample(Object value) {
892 example = value;
893 return this;
894 }
895
896 /**
897 * Bean property setter: <property>exclusiveMaximum</property>.
898 *
899 * @param value
900 * The new value for this property.
901 * <br>Can be <jk>null</jk> to unset the property.
902 * @return This object
903 */
904 public SchemaInfo setExclusiveMaximum(Boolean value) {
905 exclusiveMaximum = value;
906 return this;
907 }
908
909 /**
910 * Bean property setter: <property>exclusiveMinimum</property>.
911 *
912 * @param value
913 * The new value for this property.
914 * <br>Can be <jk>null</jk> to unset the property.
915 * @return This object
916 */
917 public SchemaInfo setExclusiveMinimum(Boolean value) {
918 exclusiveMinimum = value;
919 return this;
920 }
921
922 /**
923 * Bean property setter: <property>externalDocs</property>.
924 *
925 * @param value
926 * The new value for this property.
927 * <br>Can be <jk>null</jk> to unset the property.
928 * @return This object
929 */
930 public SchemaInfo setExternalDocs(ExternalDocumentation value) {
931 externalDocs = value;
932 return this;
933 }
934
935 /**
936 * Bean property setter: <property>format</property>.
937 *
938 * @param value
939 * The new value for this property.
940 * <br>Can be <jk>null</jk> to unset the property.
941 * <br>Formats defined by the OAS include:
942 * <ul>
943 * <li><js>"int32"</js>
944 * <li><js>"int64"</js>
945 * <li><js>"float"</js>
946 * <li><js>"double"</js>
947 * <li><js>"byte"</js>
948 * <li><js>"binary"</js>
949 * <li><js>"date"</js>
950 * <li><js>"date-time"</js>
951 * <li><js>"password"</js>
952 * </ul>
953 * @return This object
954 */
955 public SchemaInfo setFormat(String value) {
956 format = value;
957 return this;
958 }
959
960 /**
961 * Bean property setter: <property>items</property>.
962 *
963 * @param value
964 * The new value for this property.
965 * <br>Can be <jk>null</jk> to unset the property.
966 * @return This object
967 */
968 public SchemaInfo setItems(Items value) {
969 items = value;
970 return this;
971 }
972
973 /**
974 * Bean property setter: <property>maximum</property>.
975 *
976 * @param value
977 * The new value for this property.
978 * <br>Can be <jk>null</jk> to unset the property.
979 * @return This object
980 */
981 public SchemaInfo setMaximum(Number value) {
982 maximum = value;
983 return this;
984 }
985
986 /**
987 * Bean property setter: <property>maxItems</property>.
988 *
989 * @param value
990 * The new value for this property.
991 * <br>Can be <jk>null</jk> to unset the property.
992 * @return This object
993 */
994 public SchemaInfo setMaxItems(Integer value) {
995 maxItems = value;
996 return this;
997 }
998
999 /**
1000 * Bean property setter: <property>maxLength</property>.
1001 *
1002 * @param value
1003 * The new value for this property.
1004 * <br>Can be <jk>null</jk> to unset the property.
1005 * @return This object
1006 */
1007 public SchemaInfo setMaxLength(Integer value) {
1008 maxLength = value;
1009 return this;
1010 }
1011
1012 /**
1013 * Bean property setter: <property>maxProperties</property>.
1014 *
1015 * @param value
1016 * The new value for this property.
1017 * <br>Can be <jk>null</jk> to unset the property.
1018 * @return This object
1019 */
1020 public SchemaInfo setMaxProperties(Integer value) {
1021 maxProperties = value;
1022 return this;
1023 }
1024
1025 /**
1026 * Bean property setter: <property>minimum</property>.
1027 *
1028 * @param value
1029 * The new value for this property.
1030 * <br>Can be <jk>null</jk> to unset the property.
1031 * @return This object
1032 */
1033 public SchemaInfo setMinimum(Number value) {
1034 minimum = value;
1035 return this;
1036 }
1037
1038 /**
1039 * Bean property setter: <property>minItems</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 setMinItems(Integer value) {
1047 minItems = value;
1048 return this;
1049 }
1050
1051 /**
1052 * Bean property setter: <property>minLength</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 setMinLength(Integer value) {
1060 minLength = value;
1061 return this;
1062 }
1063
1064 /**
1065 * Bean property setter: <property>minProperties</property>.
1066 *
1067 * @param value
1068 * The new value for this property.
1069 * <br>Can be <jk>null</jk> to unset the property.
1070 * @return This object
1071 */
1072 public SchemaInfo setMinProperties(Integer value) {
1073 minProperties = value;
1074 return this;
1075 }
1076
1077 /**
1078 * Bean property setter: <property>multipleOf</property>.
1079 *
1080 * @param value
1081 * The new value for this property.
1082 * <br>Can be <jk>null</jk> to unset the property.
1083 * @return This object
1084 */
1085 public SchemaInfo setMultipleOf(Number value) {
1086 multipleOf = value;
1087 return this;
1088 }
1089
1090 /**
1091 * Bean property setter: <property>not</property>.
1092 *
1093 * @param value
1094 * The new value for this property.
1095 * <br>Can be <jk>null</jk> to unset the property.
1096 * @return This object
1097 */
1098 public SchemaInfo setNot(SchemaInfo value) {
1099 not = value;
1100 return this;
1101 }
1102
1103 /**
1104 * Bean property setter: <property>nullable</property>.
1105 *
1106 * @param value
1107 * The new value for this property.
1108 * <br>Can be <jk>null</jk> to unset the property.
1109 * @return This object
1110 */
1111 public SchemaInfo setNullable(Boolean value) {
1112 nullable = value;
1113 return this;
1114 }
1115
1116 /**
1117 * Bean property setter: <property>allOf</property>.
1118 *
1119 * @param value
1120 * The new value for this property.
1121 * <br>Can be <jk>null</jk> to unset the property.
1122 * @return This object
1123 */
1124 public SchemaInfo setOneOf(Collection<Object> value) {
1125 oneOf.clear();
1126 if (nn(value))
1127 oneOf.addAll(value);
1128 return this;
1129 }
1130
1131 /**
1132 * Bean property setter: <property>pattern</property>.
1133 *
1134 * <p>
1135 * This string SHOULD be a valid regular expression.
1136 *
1137 * @param value
1138 * The new value for this property.
1139 * <br>Can be <jk>null</jk> to unset the property.
1140 * @return This object
1141 */
1142 public SchemaInfo setPattern(String value) {
1143 pattern = value;
1144 return this;
1145 }
1146
1147 /**
1148 * Bean property setter: <property>properties</property>.
1149 *
1150 * @param value
1151 * The new value for this property.
1152 * <br>Can be <jk>null</jk> to unset the property.
1153 * @return This object
1154 */
1155 public SchemaInfo setProperties(Map<String,SchemaInfo> value) {
1156 properties = copyOf(value);
1157 return this;
1158 }
1159
1160 /**
1161 * Bean property setter: <property>readOnly</property>.
1162 *
1163 * @param value
1164 * The new value for this property.
1165 * <br>Can be <jk>null</jk> to unset the property.
1166 * @return This object
1167 */
1168 public SchemaInfo setReadOnly(Boolean value) {
1169 readOnly = value;
1170 return this;
1171 }
1172
1173 /**
1174 * Bean property setter: <property>$ref</property>.
1175 *
1176 * @param value
1177 * The new value for this property.
1178 * <br>Can be <jk>null</jk> to unset the property.
1179 * @return This object
1180 */
1181 @Beanp("$ref")
1182 public SchemaInfo setRef(Object value) {
1183 ref = s(value);
1184 return this;
1185 }
1186
1187 /**
1188 * Bean property setter: <property>required</property>.
1189 *
1190 * <p>
1191 * The list of required properties.
1192 *
1193 * @param value
1194 * The new value for this property.
1195 * <br>Valid values:
1196 * <ul>
1197 * <li><js>"http"</js>
1198 * <li><js>"https"</js>
1199 * <li><js>"ws"</js>
1200 * <li><js>"wss"</js>
1201 * </ul>
1202 * <br>Can be <jk>null</jk> to unset the property.
1203 * @return This object
1204 */
1205 public SchemaInfo setRequired(Collection<String> value) {
1206 required.clear();
1207 if (nn(value))
1208 required.addAll(value);
1209 return this;
1210 }
1211
1212 /**
1213 * Bean property setter: <property>title</property>.
1214 *
1215 * @param value
1216 * The new value for this property.
1217 * <br>Can be <jk>null</jk> to unset the property.
1218 * @return This object
1219 */
1220 public SchemaInfo setTitle(String value) {
1221 title = value;
1222 return this;
1223 }
1224
1225 /**
1226 * Bean property setter: <property>type</property>.
1227 *
1228 * @param value
1229 * The new value for this property.
1230 * <br>Can be <jk>null</jk> to unset the property.
1231 * <br>Possible values include:
1232 * <ul>
1233 * <li><js>"object"</js>
1234 * <li><js>"string"</js>
1235 * <li><js>"number"</js>
1236 * <li><js>"integer"</js>
1237 * <li><js>"boolean"</js>
1238 * <li><js>"array"</js>
1239 * <li><js>"file"</js>
1240 * </ul>
1241 * @return This object
1242 */
1243 public SchemaInfo setType(String value) {
1244 type = value;
1245 return this;
1246 }
1247
1248 /**
1249 * Bean property setter: <property>uniqueItems</property>.
1250 *
1251 * @param value
1252 * The new value for this property.
1253 * <br>Can be <jk>null</jk> to unset the property.
1254 * @return This object
1255 */
1256 public SchemaInfo setUniqueItems(Boolean value) {
1257 uniqueItems = value;
1258 return this;
1259 }
1260
1261 /**
1262 * Bean property setter: <property>WriteOnly</property>.
1263 *
1264 * @param value
1265 * The new value for this property.
1266 * <br>Can be <jk>null</jk> to unset the property.
1267 * @return This object
1268 */
1269 public SchemaInfo setWriteOnly(Boolean value) {
1270 writeOnly = value;
1271 return this;
1272 }
1273
1274 /**
1275 * Bean property setter: <property>xml</property>.
1276 *
1277 * @param value
1278 * The new value for this property.
1279 * <br>Can be <jk>null</jk> to unset the property.
1280 * @return This object
1281 */
1282 public SchemaInfo setXml(Xml value) {
1283 xml = value;
1284 return this;
1285 }
1286
1287 @Override /* Overridden from OpenApiElement */
1288 public SchemaInfo strict() {
1289 super.strict();
1290 return this;
1291 }
1292
1293 @Override /* Overridden from OpenApiElement */
1294 public SchemaInfo strict(Object value) {
1295 super.strict(value);
1296 return this;
1297 }
1298 }