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.jsonschema; 018 019import static org.apache.juneau.commons.utils.CollectionUtils.*; 020import static org.apache.juneau.commons.utils.Shorts.*; 021import static org.apache.juneau.commons.utils.StringUtils.*; 022 023import java.lang.reflect.*; 024import java.net.*; 025import java.util.*; 026 027import org.apache.juneau.commons.bean.*; 028import org.apache.juneau.commons.reflect.*; 029import org.apache.juneau.marshall.*; 030import org.apache.juneau.marshall.marshaller.*; 031import org.apache.juneau.marshall.parser.*; 032import org.apache.juneau.marshall.serializer.*; 033import org.apache.juneau.marshall.swap.spi.*; 034 035/** 036 * Represents a top-level schema object bean in the JSON-Schema core specification. 037 * 038 * <p> 039 * This implementation follows the JSON Schema Draft 2020-12 specification. 040 * 041 * <h5 class='section'>Example:</h5> 042 * <p class='bjava'> 043 * <jc>// Create a simple schema for a person object</jc> 044 * JsonSchema <jv>schema</jv> = <jk>new</jk> JsonSchema() 045 * .setIdUri(<js>"https://example.com/person.schema.json"</js>) 046 * .setSchemaVersionUri(<js>"https://json-schema.org/draft/2020-12/schema"</js>) 047 * .setTitle(<js>"Person"</js>) 048 * .setDescription(<js>"A person object"</js>) 049 * .setType(JsonType.<jsf>OBJECT</jsf>) 050 * .addProperties( 051 * <jk>new</jk> JsonSchemaProperty(<js>"firstName"</js>, JsonType.<jsf>STRING</jsf>) 052 * .setMinLength(1) 053 * .setMaxLength(50), 054 * <jk>new</jk> JsonSchemaProperty(<js>"lastName"</js>, JsonType.<jsf>STRING</jsf>) 055 * .setMinLength(1) 056 * .setMaxLength(50), 057 * <jk>new</jk> JsonSchemaProperty(<js>"age"</js>, JsonType.<jsf>INTEGER</jsf>) 058 * .setMinimum(0) 059 * .setExclusiveMaximum(150) 060 * ) 061 * .addRequired(<js>"firstName"</js>, <js>"lastName"</js>); 062 * 063 * <jc>// Serialize to JSON Schema</jc> 064 * String <jv>json</jv> = JsonSerializer.<jsf>DEFAULT</jsf>.write(<jv>schema</jv>); 065 * </p> 066 * 067 * <p> 068 * Output: 069 * <p class='bjson'> 070 * { 071 * <js>"$id"</js>: <js>"https://example.com/person.schema.json"</js>, 072 * <js>"$schema"</js>: <js>"https://json-schema.org/draft/2020-12/schema"</js>, 073 * <js>"title"</js>: <js>"Person"</js>, 074 * <js>"description"</js>: <js>"A person object"</js>, 075 * <js>"type"</js>: <js>"object"</js>, 076 * <js>"properties"</js>: { 077 * <js>"firstName"</js>: { 078 * <js>"type"</js>: <js>"string"</js>, 079 * <js>"minLength"</js>: 1, 080 * <js>"maxLength"</js>: 50 081 * }, 082 * <js>"lastName"</js>: { 083 * <js>"type"</js>: <js>"string"</js>, 084 * <js>"minLength"</js>: 1, 085 * <js>"maxLength"</js>: 50 086 * }, 087 * <js>"age"</js>: { 088 * <js>"type"</js>: <js>"integer"</js>, 089 * <js>"minimum"</js>: 0, 090 * <js>"exclusiveMaximum"</js>: 150 091 * } 092 * }, 093 * <js>"required"</js>: [<js>"firstName"</js>, <js>"lastName"</js>] 094 * } 095 * </p> 096 * 097 * <h5 class='section'>Key Features:</h5> 098 * <ul class='spaced-list'> 099 * <li><b>Draft 2020-12 Support:</b> Includes all properties from the latest JSON Schema specification 100 * <li><b>Backward Compatibility:</b> Deprecated Draft 04 properties (like <c>id</c> and <c>definitions</c>) are still supported 101 * <li><b>Fluent API:</b> All setter methods return <c>this</c> for method chaining 102 * <li><b>Type Safety:</b> Uses enums and typed collections for validation 103 * <li><b>Serialization:</b> Can be serialized to any format supported by Juneau (JSON, XML, HTML, etc.) 104 * <li><b>Auto Generation:</b> Use {@link JsonSchemaBeanGenerator} to generate schemas from Java types 105 * </ul> 106 * 107 * <h5 class='section'>Common Use Cases:</h5> 108 * 109 * <p><b>1. Simple Type Constraints:</b> 110 * <p class='bjava'> 111 * <jc>// String with length constraints</jc> 112 * JsonSchema <jv>schema</jv> = <jk>new</jk> JsonSchema() 113 * .setType(JsonType.<jsf>STRING</jsf>) 114 * .setMinLength(5) 115 * .setMaxLength(100) 116 * .setPattern(<js>"^[A-Za-z]+$"</js>); 117 * </p> 118 * 119 * <p><b>2. Numeric Ranges:</b> 120 * <p class='bjava'> 121 * <jc>// Number between 0 and 100 (exclusive)</jc> 122 * JsonSchema <jv>schema</jv> = <jk>new</jk> JsonSchema() 123 * .setType(JsonType.<jsf>NUMBER</jsf>) 124 * .setExclusiveMinimum(0) 125 * .setExclusiveMaximum(100) 126 * .setMultipleOf(0.5); 127 * </p> 128 * 129 * <p><b>3. Enumerations:</b> 130 * <p class='bjava'> 131 * <jc>// Status field with allowed values</jc> 132 * JsonSchema <jv>schema</jv> = <jk>new</jk> JsonSchema() 133 * .setType(JsonType.<jsf>STRING</jsf>) 134 * .addEnum(<js>"pending"</js>, <js>"active"</js>, <js>"completed"</js>); 135 * </p> 136 * 137 * <p><b>4. Arrays:</b> 138 * <p class='bjava'> 139 * <jc>// Array of strings with constraints</jc> 140 * JsonSchema <jv>schema</jv> = <jk>new</jk> JsonSchema() 141 * .setType(JsonType.<jsf>ARRAY</jsf>) 142 * .setItems(<jk>new</jk> JsonSchema().setType(JsonType.<jsf>STRING</jsf>)) 143 * .setMinItems(1) 144 * .setMaxItems(10) 145 * .setUniqueItems(<jk>true</jk>); 146 * </p> 147 * 148 * <p><b>5. Conditional Schemas (Draft 07+):</b> 149 * <p class='bjava'> 150 * <jc>// Different validation based on country</jc> 151 * JsonSchema <jv>schema</jv> = <jk>new</jk> JsonSchema() 152 * .setType(JsonType.<jsf>OBJECT</jsf>) 153 * .addProperties( 154 * <jk>new</jk> JsonSchemaProperty(<js>"country"</js>, JsonType.<jsf>STRING</jsf>), 155 * <jk>new</jk> JsonSchemaProperty(<js>"postalCode"</js>, JsonType.<jsf>STRING</jsf>) 156 * ) 157 * .setIf(<jk>new</jk> JsonSchema() 158 * .addProperties(<jk>new</jk> JsonSchemaProperty(<js>"country"</js>).setConst(<js>"USA"</js>)) 159 * ) 160 * .setThen(<jk>new</jk> JsonSchema() 161 * .addProperties(<jk>new</jk> JsonSchemaProperty(<js>"postalCode"</js>).setPattern(<js>"^[0-9]{5}$"</js>)) 162 * ); 163 * </p> 164 * 165 * <p><b>6. Reusable Definitions:</b> 166 * <p class='bjava'> 167 * <jc>// Schema with reusable components using $defs</jc> 168 * JsonSchema <jv>schema</jv> = <jk>new</jk> JsonSchema() 169 * .setType(JsonType.<jsf>OBJECT</jsf>) 170 * .addDef(<js>"address"</js>, <jk>new</jk> JsonSchema() 171 * .setType(JsonType.<jsf>OBJECT</jsf>) 172 * .addProperties( 173 * <jk>new</jk> JsonSchemaProperty(<js>"street"</js>, JsonType.<jsf>STRING</jsf>), 174 * <jk>new</jk> JsonSchemaProperty(<js>"city"</js>, JsonType.<jsf>STRING</jsf>) 175 * ) 176 * ) 177 * .addProperties( 178 * <jk>new</jk> JsonSchemaProperty(<js>"billingAddress"</js>) 179 * .setRef(<js>"#/$defs/address"</js>), 180 * <jk>new</jk> JsonSchemaProperty(<js>"shippingAddress"</js>) 181 * .setRef(<js>"#/$defs/address"</js>) 182 * ); 183 * </p> 184 * 185 * <h5 class='section'>Migration from Draft 04:</h5> 186 * <ul class='spaced-list'> 187 * <li>Use {@link #setIdUri(Object)} instead of {@link #setId(Object)} (deprecated) 188 * <li>Use {@link #setDefs(Map)} instead of {@link #setDefinitions(Map)} (deprecated but still works) 189 * <li>Use {@link #setExclusiveMaximum(Number)} with a numeric value instead of a boolean flag 190 * <li>Use {@link #setExclusiveMinimum(Number)} with a numeric value instead of a boolean flag 191 * </ul> 192 * 193 * <h5 class='section'>See Also:</h5><ul> 194 * <li class='link'><a href="https://json-schema.org/draft/2020-12/json-schema-core.html">JSON Schema 2020-12 Core</a> 195 * <li class='link'><a href="https://json-schema.org/draft/2020-12/json-schema-validation.html">JSON Schema 2020-12 Validation</a> 196 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanJsonSchema">juneau-bean-jsonschema</a> 197 * </ul> 198 * 199 * @param <SELF> The self type for fluent setters. 200 */ 201@Marshalled(typeName = "schema") 202@SuppressWarnings({ 203 "java:S116", // Field names follow OpenAPI/JSON Schema spec 204 "java:S119", // 'SELF' (CRTP self-type) is intentional and clearer than a single-letter name. 205 "java:S1133", // Kept for Draft 04 backward compatibility, will be removed in future version 206 "java:S1452", // The static factories of(Type)/of(Class) and the keyword accessors return JsonSchema<?> because SELF is unknown to callers. 207 "java:S6539" // Monster class; JsonSchema intentionally models the entire JSON Schema Draft 2020-12 keyword set as one cohesive bean 208}) 209public class JsonSchema<SELF extends JsonSchema<SELF>> { 210 211 /** 212 * Used during parsing to convert the <property>additionalItems</property> property to the correct class type. 213 * 214 * <ul class='spaced-list'> 215 * <li> 216 * If parsing a JSON-array, converts to a {@link JsonSchemaArray}. 217 * <li> 218 * If parsing a JSON-boolean, converts to a {@link Boolean}. 219 * </ul> 220 * 221 * <p> 222 * Serialization method is a no-op. 223 */ 224 public static class BooleanOrSchemaArraySwap extends ObjectSwap<Object,Object> { 225 226 @Override /* Overridden from ObjectSwap */ 227 public Object swap(MarshallingSession session, Object o) throws SerializeException { 228 return o; 229 } 230 231 @Override /* Overridden from ObjectSwap */ 232 public Object unswap(MarshallingSession session, Object o, ClassMeta<?> hint) throws ParseException { 233 var cm = session.getClassMeta(o instanceof Collection ? JsonSchemaArray.class : Boolean.class); 234 return session.convertToType(o, cm); 235 } 236 } 237 238 /** 239 * Used during parsing to convert the <property>additionalProperties</property> property to the correct class type. 240 * 241 * <ul class='spaced-list'> 242 * <li> 243 * If parsing a JSON-object, converts to a {@link JsonSchema}. 244 * <li> 245 * If parsing a JSON-boolean, converts to a {@link Boolean}. 246 * </ul> 247 * 248 * <p> 249 * Serialization method is a no-op. 250 */ 251 public static class BooleanOrSchemaSwap extends ObjectSwap<Object,Object> { 252 253 @Override /* Overridden from ObjectSwap */ 254 public Object swap(MarshallingSession session, Object o) throws SerializeException { 255 return o; 256 } 257 258 @Override /* Overridden from ObjectSwap */ 259 public Object unswap(MarshallingSession session, Object o, ClassMeta<?> hint) throws ParseException { 260 var cm = session.getClassMeta(o instanceof Boolean ? Boolean.class : JsonSchema.class); 261 return session.convertToType(o, cm); 262 } 263 } 264 265 /** 266 * Used during parsing to convert the <property>items</property> property to the correct class type. 267 * 268 * <ul class='spaced-list'> 269 * <li> 270 * If parsing a JSON-array, converts to a {@link JsonSchemaArray}. 271 * <li> 272 * If parsing a JSON-object, converts to a {@link JsonSchema}. 273 * </ul> 274 * 275 * <p> 276 * Serialization method is a no-op. 277 */ 278 public static class JsonSchemaOrSchemaArraySwap extends ObjectSwap<Object,Object> { 279 280 @Override /* Overridden from ObjectSwap */ 281 public Object swap(MarshallingSession session, Object o) throws SerializeException { 282 return o; 283 } 284 285 @Override /* Overridden from ObjectSwap */ 286 public Object unswap(MarshallingSession session, Object o, ClassMeta<?> hint) throws ParseException { 287 var cm = session.getClassMeta(o instanceof Collection ? JsonSchemaArray.class : JsonSchema.class); 288 return session.convertToType(o, cm); 289 } 290 } 291 292 /** 293 * Used during parsing to convert the <property>type</property> property to the correct class type. 294 * 295 * <ul class='spaced-list'> 296 * <li> 297 * If parsing a JSON-array, converts to a {@link JsonTypeArray}. 298 * <li> 299 * If parsing a JSON-object, converts to a {@link JsonType}. 300 * </ul> 301 * 302 * <p> 303 * Serialization method is a no-op. 304 */ 305 public static class JsonTypeOrJsonTypeArraySwap extends ObjectSwap<Object,Object> { 306 307 @Override /* Overridden from ObjectSwap */ 308 public Object swap(MarshallingSession session, Object o) throws SerializeException { 309 return o; 310 } 311 312 @Override /* Overridden from ObjectSwap */ 313 public Object unswap(MarshallingSession session, Object o, ClassMeta<?> hint) throws ParseException { 314 var cm = session.getClassMeta(o instanceof Collection ? JsonTypeArray.class : JsonType.class); 315 return session.convertToType(o, cm); 316 } 317 } 318 319 // @formatter:off 320 private String name; // Property name. Not serialized. 321 private URI idUri; // Draft 2020-12: $id 322 private URI id; // Draft 04: id (deprecated but kept for compatibility) 323 private URI schemaVersion; 324 private String title; 325 private String summary; 326 private String description; 327 private JsonType typeJsonType; // JsonType representation of type 328 private JsonTypeArray typeJsonTypeArray; // JsonTypeArray representation of type 329 private Map<String,JsonSchema<?>> definitions; // Retained for backward compatibility 330 private Map<String,JsonSchema<?>> defs; // Draft 2020-12: $defs 331 private Map<String,JsonSchema<?>> properties; 332 private Map<String,JsonSchema<?>> patternProperties; 333 private Map<String,JsonSchema<?>> dependencies; // Retained for backward compatibility 334 private Map<String,JsonSchema<?>> dependentSchemas; // Draft 2019-09+ 335 private Map<String,List<String>> dependentRequired; // Draft 2019-09+ 336 private JsonSchema<?> itemsSchema; // JsonSchema representation of items 337 private JsonSchemaArray itemsSchemaArray; // JsonSchemaArray representation of items 338 private JsonSchemaArray prefixItems; // Draft 2020-12: replaces tuple validation 339 private Number multipleOf; 340 private Number maximum; 341 private Number exclusiveMaximum; // Draft 06+: changed from Boolean to Number 342 private Number minimum; 343 private Number exclusiveMinimum; // Draft 06+: changed from Boolean to Number 344 private Integer maxLength; 345 private Integer minLength; 346 private String pattern; 347 private Boolean additionalItemsBoolean; // Boolean representation of additionalItems 348 private JsonSchemaArray additionalItemsSchemaArray; // JsonSchemaArray representation of additionalItems 349 private JsonSchema<?> unevaluatedItems; // Draft 2019-09+ 350 private Integer maxItems; 351 private Integer minItems; 352 private Boolean uniqueItems; 353 private Integer maxProperties; 354 private Integer minProperties; 355 private List<String> required; 356 private Boolean additionalPropertiesBoolean; // Boolean representation of additionalProperties 357 private JsonSchema<?> additionalPropertiesSchema; // JsonSchema representation of additionalProperties 358 private JsonSchema<?> unevaluatedProperties; // Draft 2019-09+ 359 private List<Object> enum_; // Changed to Object to support any type 360 private Object const_; // Draft 06+ 361 private List<Object> examples; // Draft 06+ 362 private List<JsonSchema<?>> allOf; 363 private List<JsonSchema<?>> anyOf; 364 private List<JsonSchema<?>> oneOf; 365 private JsonSchema<?> not; 366 private JsonSchema<?> if_; // Draft 07+ 367 private JsonSchema<?> then_; // Draft 07+ 368 private JsonSchema<?> else_; // Draft 07+ 369 private Boolean readOnly; // Draft 07+ 370 private Boolean writeOnly; // Draft 07+ 371 private String format; // Annotation-level keyword 372 private String comment; // Draft 07+, serialized as $comment 373 private Boolean deprecated; // Draft 2019-09+ 374 private String contentMediaType; // Draft 07+ 375 376 private String contentEncoding; // Draft 07+ 377 378 private URI ref; 379 380 private JsonSchemaMap schemaMap; 381 382 private JsonSchema<?> master = this; 383 // @formatter:on 384 385 /** 386 * Default constructor. 387 */ 388 public JsonSchema() { /* Empty constructor. */ } 389 390 @SuppressWarnings({ 391 "unchecked" // Standard CRTP self cast; SELF is always the concrete subclass. 392 }) 393 private SELF self() { 394 return (SELF) this; 395 } 396 397 /** 398 * Generates a {@link JsonSchema} bean from the specified type using {@link JsonSchemaBeanGenerator#DEFAULT}. 399 * 400 * @param type The type to generate a schema for. Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 401 * @return The generated schema bean, or <jk>null</jk> if a schema could not be generated for the type. 402 */ 403 public static JsonSchema<?> of(Type type) { 404 return JsonSchemaBeanGenerator.DEFAULT.generate(type); 405 } 406 407 /** 408 * Generates a {@link JsonSchema} bean from the specified class using {@link JsonSchemaBeanGenerator#DEFAULT}. 409 * 410 * @param type The class to generate a schema for. Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 411 * @return The generated schema bean, or <jk>null</jk> if a schema could not be generated for the class. 412 */ 413 public static JsonSchema<?> of(Class<?> type) { 414 return JsonSchemaBeanGenerator.DEFAULT.generate(type); 415 } 416 417 /** 418 * Bean property appender: <property>additionalItems</property>. 419 * 420 * @param value 421 * The list of items to append to the <property>additionalItems</property> property on this bean. 422 * @return This object. 423 */ 424 public SELF addAdditionalItems(JsonSchema<?>...value) { 425 if (this.additionalItemsSchemaArray == null) 426 this.additionalItemsSchemaArray = new JsonSchemaArray(); 427 this.additionalItemsSchemaArray.addAll(value); 428 setMasterOn(value); 429 return self(); 430 } 431 432 /** 433 * Bean property appender: <property>allOf</property>. 434 * 435 * @param value The list of items to append to the <property>allOf</property> property on this bean. 436 * @return This object. 437 */ 438 public SELF addAllOf(JsonSchema<?>...value) { 439 setMasterOn(value); 440 this.allOf = addAll(this.allOf, value); 441 return self(); 442 } 443 444 /** 445 * Bean property appender: <property>allOf</property>. 446 * 447 * @param value The collection of items to append to the <property>allOf</property> property on this bean. 448 * @return This object. 449 */ 450 public SELF addAllOf(Collection<JsonSchema<?>> value) { 451 setMasterOn(value); 452 this.allOf = addAll(this.allOf, value == null ? null : new ArrayList<>(value)); 453 return self(); 454 } 455 456 /** 457 * Bean property appender: <property>anyOf</property>. 458 * 459 * @param value The list of items to append to the <property>anyOf</property> property on this bean. 460 * @return This object. 461 */ 462 public SELF addAnyOf(JsonSchema<?>...value) { 463 if (this.anyOf == null) 464 this.anyOf = new LinkedList<>(); 465 setMasterOn(value); 466 for (var s : value) 467 this.anyOf.add(s); 468 return self(); 469 } 470 471 /** 472 * Bean property appender: <property>anyOf</property>. 473 * 474 * @param value The collection of items to append to the <property>anyOf</property> property on this bean. 475 * @return This object. 476 */ 477 public SELF addAnyOf(Collection<JsonSchema<?>> value) { 478 if (this.anyOf == null) 479 this.anyOf = new LinkedList<>(); 480 setMasterOn(value); 481 this.anyOf.addAll(value); 482 return self(); 483 } 484 485 /** 486 * Bean property appender: <property>$defs</property>. 487 * 488 * @param name The key in the defs map entry. Can be <jk>null</jk> ({@link LinkedHashMap} tolerates a <jk>null</jk> key). 489 * @param value The value in the defs map entry. Can be <jk>null</jk> (stored as <jk>null</jk>). 490 * @return This object. 491 */ 492 public SELF addDef(String name, JsonSchema<?> value) { 493 if (this.defs == null) 494 this.defs = map(); 495 this.defs.put(name, value); 496 setMasterOn(value); 497 return self(); 498 } 499 500 /** 501 * Bean property appender: <property>definitions</property>. 502 * 503 * @param name The key in the definitions map entry. Can be <jk>null</jk> ({@link LinkedHashMap} tolerates a <jk>null</jk> key). 504 * @param value The value in the definitions map entry. Can be <jk>null</jk> (stored as <jk>null</jk>). 505 * @return This object. 506 */ 507 public SELF addDefinition(String name, JsonSchema<?> value) { 508 if (this.definitions == null) 509 this.definitions = map(); 510 this.definitions.put(name, value); 511 setMasterOn(value); 512 return self(); 513 } 514 515 /** 516 * Bean property appender: <property>dependencies</property>. 517 * 518 * @param name The key of the entry in the dependencies map. Can be <jk>null</jk> ({@link LinkedHashMap} tolerates a <jk>null</jk> key). 519 * @param value The value of the entry in the dependencies map. Can be <jk>null</jk> (stored as <jk>null</jk>). 520 * @return This object. 521 */ 522 public SELF addDependency(String name, JsonSchema<?> value) { 523 if (this.dependencies == null) 524 this.dependencies = map(); 525 this.dependencies.put(name, value); 526 setMasterOn(value); 527 return self(); 528 } 529 530 /** 531 * Bean property appender: <property>dependentRequired</property>. 532 * 533 * @param name The key of the entry in the dependentRequired map. Can be <jk>null</jk> ({@link LinkedHashMap} tolerates a <jk>null</jk> key). 534 * @param value The value of the entry in the dependentRequired map. Can be <jk>null</jk> (stored as <jk>null</jk>). 535 * @return This object. 536 */ 537 public SELF addDependentRequired(String name, List<String> value) { 538 if (this.dependentRequired == null) 539 this.dependentRequired = map(); 540 this.dependentRequired.put(name, value); 541 return self(); 542 } 543 544 /** 545 * Bean property appender: <property>dependentSchemas</property>. 546 * 547 * @param name The key of the entry in the dependentSchemas map. Can be <jk>null</jk> ({@link LinkedHashMap} tolerates a <jk>null</jk> key). 548 * @param value The value of the entry in the dependentSchemas map. Can be <jk>null</jk> (stored as <jk>null</jk>). 549 * @return This object. 550 */ 551 public SELF addDependentSchema(String name, JsonSchema<?> value) { 552 if (this.dependentSchemas == null) 553 this.dependentSchemas = map(); 554 this.dependentSchemas.put(name, value); 555 setMasterOn(value); 556 return self(); 557 } 558 559 /** 560 * Bean property appender: <property>enum</property>. 561 * 562 * @param value The list of items to append to the <property>enum</property> property on this bean. 563 * @return This object. 564 */ 565 public SELF addEnum(Object...value) { 566 if (this.enum_ == null) 567 this.enum_ = new LinkedList<>(); 568 for (var e : value) 569 this.enum_.add(e); 570 return self(); 571 } 572 573 /** 574 * Bean property appender: <property>enum</property>. 575 * 576 * @param value The collection of items to append to the <property>enum</property> property on this bean. 577 * @return This object. 578 */ 579 public SELF addEnum(Collection<Object> value) { 580 if (this.enum_ == null) 581 this.enum_ = new LinkedList<>(); 582 this.enum_.addAll(value); 583 return self(); 584 } 585 586 /** 587 * Bean property appender: <property>examples</property>. 588 * 589 * @param value The list of items to append to the <property>examples</property> property on this bean. 590 * @return This object. 591 */ 592 public SELF addExamples(Object...value) { 593 if (this.examples == null) 594 this.examples = new LinkedList<>(); 595 for (var e : value) 596 this.examples.add(e); 597 return self(); 598 } 599 600 /** 601 * Bean property appender: <property>examples</property>. 602 * 603 * @param value The collection of items to append to the <property>examples</property> property on this bean. 604 * @return This object. 605 */ 606 public SELF addExamples(Collection<Object> value) { 607 if (this.examples == null) 608 this.examples = new LinkedList<>(); 609 this.examples.addAll(value); 610 return self(); 611 } 612 613 /** 614 * Bean property appender: <property>items</property>. 615 * 616 * @param value The list of items to append to the <property>items</property> property on this bean. 617 * @return This object. 618 */ 619 public SELF addItems(JsonSchema<?>...value) { 620 if (this.itemsSchemaArray == null) 621 this.itemsSchemaArray = new JsonSchemaArray(); 622 this.itemsSchemaArray.addAll(value); 623 setMasterOn(value); 624 return self(); 625 } 626 627 /** 628 * Bean property appender: <property>oneOf</property>. 629 * 630 * @param value The list of items to append to the <property>oneOf</property> property on this bean. 631 * @return This object. 632 */ 633 public SELF addOneOf(JsonSchema<?>...value) { 634 if (this.oneOf == null) 635 this.oneOf = new LinkedList<>(); 636 setMasterOn(value); 637 for (var s : value) 638 this.oneOf.add(s); 639 return self(); 640 } 641 642 /** 643 * Bean property appender: <property>oneOf</property>. 644 * 645 * @param value The collection of items to append to the <property>oneOf</property> property on this bean. 646 * @return This object. 647 */ 648 public SELF addOneOf(Collection<JsonSchema<?>> value) { 649 if (this.oneOf == null) 650 this.oneOf = new LinkedList<>(); 651 setMasterOn(value); 652 this.oneOf.addAll(value); 653 return self(); 654 } 655 656 /** 657 * Bean property appender: <property>patternProperties</property>. 658 * 659 * <p> 660 * Properties must have their <property>name</property> property set to the pattern string when using this method. 661 * 662 * @param value The list of items to append to the <property>patternProperties</property> property on this bean. 663 * @return This object. 664 * @throws BeanRuntimeException If property is found without a set <property>name</property> property. 665 */ 666 public SELF addPatternProperties(JsonSchemaProperty<?>...value) { 667 if (this.patternProperties == null) 668 this.patternProperties = map(); 669 for (var p : value) { 670 if (p.getName() == null) 671 throw brex(JsonSchema.class, "Invalid property passed to JsonSchema.addProperties(). Property name was null."); 672 setMasterOn(p); 673 this.patternProperties.put(p.getName(), p); 674 } 675 return self(); 676 } 677 678 /** 679 * Bean property appender: <property>patternProperties</property>. 680 * 681 * <p> 682 * Unlike {@link #addPatternProperties(JsonSchemaProperty...)}, this keyed form does not require the value's 683 * <property>name</property> property to be pre-set — it is set automatically from {@code name}. 684 * 685 * @param name The key in the patternProperties map entry. Can be <jk>null</jk> ({@link LinkedHashMap} tolerates a <jk>null</jk> key). 686 * @param value The value in the patternProperties map entry. Can be <jk>null</jk> (stored as <jk>null</jk>). 687 * @return This object. 688 */ 689 public SELF addPatternProperty(String name, JsonSchema<?> value) { 690 if (this.patternProperties == null) 691 this.patternProperties = map(); 692 if (value != null) { 693 setMasterOn(value); 694 value.setName(name); 695 } 696 this.patternProperties.put(name, value); 697 return self(); 698 } 699 700 /** 701 * Bean property appender: <property>prefixItems</property>. 702 * 703 * @param value The list of items to append to the <property>prefixItems</property> property on this bean. 704 * @return This object. 705 */ 706 public SELF addPrefixItems(JsonSchema<?>...value) { 707 if (this.prefixItems == null) 708 this.prefixItems = new JsonSchemaArray(); 709 this.prefixItems.addAll(value); 710 setMasterOn(value); 711 return self(); 712 } 713 714 /** 715 * Bean property appender: <property>properties</property>. 716 * 717 * <p> 718 * Properties must have their <property>name</property> property set on them when using this method. 719 * 720 * @param value The list of items to append to the <property>properties</property> property on this bean. 721 * @return This object. 722 * @throws BeanRuntimeException If property is found without a set <property>name</property> property. 723 */ 724 public SELF addProperties(JsonSchema<?>...value) { 725 if (this.properties == null) 726 this.properties = map(); 727 for (var p : value) { 728 if (p.getName() == null) 729 throw brex(JsonSchema.class, "Invalid property passed to JsonSchema.addProperties(). Property name was null."); 730 setMasterOn(p); 731 this.properties.put(p.getName(), p); 732 } 733 return self(); 734 } 735 736 /** 737 * Bean property appender: <property>properties</property>. 738 * 739 * <p> 740 * Unlike {@link #addProperties(JsonSchema...)}, this keyed form does not require the value's 741 * <property>name</property> property to be pre-set — it is set automatically from {@code name}. 742 * 743 * @param name The key in the properties map entry. Can be <jk>null</jk> ({@link LinkedHashMap} tolerates a <jk>null</jk> key). 744 * @param value The value in the properties map entry. Can be <jk>null</jk> (stored as <jk>null</jk>). 745 * @return This object. 746 */ 747 public SELF addProperty(String name, JsonSchema<?> value) { 748 if (this.properties == null) 749 this.properties = map(); 750 if (value != null) { 751 setMasterOn(value); 752 value.setName(name); 753 } 754 this.properties.put(name, value); 755 return self(); 756 } 757 758 /** 759 * Bean property appender: <property>required</property>. 760 * 761 * @param value The list of items to append to the <property>required</property> property on this bean. 762 * @return This object. 763 */ 764 public SELF addRequired(JsonSchemaProperty<?>...value) { 765 if (this.required == null) 766 this.required = new LinkedList<>(); 767 for (var p : value) 768 this.required.add(p.getName()); 769 return self(); 770 } 771 772 /** 773 * Bean property appender: <property>required</property>. 774 * 775 * @param value The list of items to append to the <property>required</property> property on this bean. 776 * @return This object. 777 */ 778 public SELF addRequired(List<String> value) { 779 if (this.required == null) 780 this.required = new LinkedList<>(); 781 value.forEach(x -> this.required.add(x)); 782 return self(); 783 } 784 785 /** 786 * Bean property appender: <property>required</property>. 787 * 788 * @param value The list of items to append to the <property>required</property> property on this bean. 789 * @return This object. 790 */ 791 public SELF addRequired(String...value) { 792 if (this.required == null) 793 this.required = new LinkedList<>(); 794 for (var r : value) 795 this.required.add(r); 796 return self(); 797 } 798 799 /** 800 * Bean property appender: <property>type</property>. 801 * 802 * @param value The list of items to append to the <property>type</property> property on this bean. 803 * @return This object. 804 */ 805 public SELF addTypes(JsonType...value) { 806 if (this.typeJsonTypeArray == null) 807 this.typeJsonTypeArray = new JsonTypeArray(); 808 this.typeJsonTypeArray.addAll(value); 809 return self(); 810 } 811 812 /** 813 * Bean property getter: <property>additionalItems</property>. 814 * 815 * @return 816 * The value of the <property>additionalItems</property> property on this bean, or <jk>null</jk> if it is 817 * not set. 818 * Can be either a {@link Boolean} or {@link JsonSchemaArray} depending on what value was used to set it. 819 */ 820 @Swap(BooleanOrSchemaArraySwap.class) 821 public Object getAdditionalItems() { 822 if (nn(additionalItemsBoolean)) 823 return additionalItemsBoolean; 824 return additionalItemsSchemaArray; 825 } 826 827 /** 828 * Bean property getter: <property>additionalItems</property>. 829 * 830 * <p> 831 * Convenience method for returning the <property>additionalItems</property> property when it is a {@link Boolean} 832 * value. 833 * 834 * @return The currently set value, or <jk>null</jk> if the property is not set, or is set as a {@link JsonSchemaArray}. 835 */ 836 @BeanIgnore 837 public Boolean getAdditionalItemsAsBoolean() { return additionalItemsBoolean; } 838 839 /** 840 * Bean property getter: <property>additionalItems</property>. 841 * 842 * <p> 843 * Convenience method for returning the <property>additionalItems</property> property when it is a 844 * {@link JsonSchemaArray} value. 845 * 846 * @return The currently set value, or <jk>null</jk> if the property is not set, or is set as a {@link Boolean}. 847 */ 848 @BeanIgnore 849 public List<JsonSchema<?>> getAdditionalItemsAsSchemaArray() { return u(additionalItemsSchemaArray); } 850 851 /** 852 * Bean property getter: <property>additionalProperties</property>. 853 * 854 * @return 855 * The value of the <property>additionalProperties</property> property on this bean, or <jk>null</jk> if it 856 * is not set. 857 * Can be either a {@link Boolean} or {@link JsonSchema} depending on what value was used to set it. 858 */ 859 @Swap(BooleanOrSchemaSwap.class) 860 public Object getAdditionalProperties() { 861 if (nn(additionalPropertiesBoolean)) 862 return additionalPropertiesBoolean; 863 return additionalPropertiesSchema; 864 } 865 866 /** 867 * Bean property getter: <property>additionalProperties</property>. 868 * 869 * <p> 870 * Convenience method for returning the <property>additionalProperties</property> property when it is a 871 * {@link Boolean} value. 872 * 873 * @return The currently set value, or <jk>null</jk> if the property is not set, or is set as a {@link JsonSchema}. 874 */ 875 @BeanIgnore 876 public Boolean getAdditionalPropertiesAsBoolean() { return additionalPropertiesBoolean; } 877 878 /** 879 * Bean property getter: <property>additionalProperties</property>. 880 * 881 * <p> 882 * Convenience method for returning the <property>additionalProperties</property> property when it is a 883 * {@link JsonSchema} value. 884 * 885 * @return The currently set value, or <jk>null</jk> if the property is not set, or is set as a {@link Boolean}. 886 */ 887 @BeanIgnore 888 public JsonSchema<?> getAdditionalPropertiesAsSchema() { return additionalPropertiesSchema; } 889 890 /** 891 * Bean property getter: <property>allOf</property>. 892 * 893 * @return The value of the <property>allOf</property> property on this bean, or <jk>null</jk> if it is not set. 894 */ 895 public List<JsonSchema<?>> getAllOf() { return u(allOf); } 896 897 /** 898 * Bean property getter: <property>anyOf</property>. 899 * 900 * @return The value of the <property>anyOf</property> property on this bean, or <jk>null</jk> if it is not set. 901 */ 902 public List<JsonSchema<?>> getAnyOf() { return u(anyOf); } 903 904 /** 905 * Bean property getter: <property>const</property>. 906 * 907 * <p> 908 * This property was added in Draft 06. 909 * 910 * @return The value of the <property>const</property> property on this bean, or <jk>null</jk> if it is not set. 911 */ 912 public Object getConst() { return const_; } 913 914 /** 915 * Bean property getter: <property>contentEncoding</property>. 916 * 917 * <p> 918 * This property was added in Draft 07. 919 * 920 * @return The value of the <property>contentEncoding</property> property on this bean, or <jk>null</jk> if it is not set. 921 */ 922 public String getContentEncoding() { return contentEncoding; } 923 924 /** 925 * Bean property getter: <property>contentMediaType</property>. 926 * 927 * <p> 928 * This property was added in Draft 07. 929 * 930 * @return The value of the <property>contentMediaType</property> property on this bean, or <jk>null</jk> if it is not set. 931 */ 932 public String getContentMediaType() { return contentMediaType; } 933 934 /** 935 * Bean property getter: <property>deprecated</property>. 936 * 937 * <p> 938 * This property was added in Draft 2019-09. 939 * 940 * @return The value of the <property>deprecated</property> property on this bean, or <jk>null</jk> if it is not set. 941 */ 942 public Boolean getDeprecated() { return deprecated; } 943 944 /** 945 * Bean property getter: <property>$comment</property>. 946 * 947 * <p> 948 * This property was added in Draft 07. 949 * 950 * @return The value of the <property>$comment</property> property on this bean, or <jk>null</jk> if it is not set. 951 */ 952 @BeanProp("$comment") 953 public String getComment() { return comment; } 954 955 /** 956 * Bean property getter: <property>definitions</property>. 957 * 958 * <p> 959 * <b>Deprecated:</b> Use {@link #getDefs()} for Draft 2020-12 compliance. 960 * This property is retained for Draft 04 backward compatibility. 961 * 962 * @return 963 * The value of the <property>definitions</property> property on this bean, or <jk>null</jk> if it is not set. 964 */ 965 public Map<String,JsonSchema<?>> getDefinitions() { 966 return nn(definitions) ? definitions : defs; // Fall back to $defs for compatibility 967 } 968 969 /** 970 * Bean property getter: <property>$defs</property>. 971 * 972 * <p> 973 * This is the Draft 2020-12 replacement for <property>definitions</property>. 974 * Both properties are supported for backward compatibility. 975 * 976 * @return The value of the <property>$defs</property> property on this bean, or <jk>null</jk> if it is not set. 977 */ 978 @BeanProp("$defs") 979 public Map<String,JsonSchema<?>> getDefs() { 980 return defs; // Return only defs, not definitions (to avoid double serialization) 981 } 982 983 /** 984 * Bean property getter: <property>dependencies</property>. 985 * 986 * @return 987 * The value of the <property>dependencies</property> property on this bean, or <jk>null</jk> if it is not set. 988 */ 989 public Map<String,JsonSchema<?>> getDependencies() { return u(dependencies); } 990 991 /** 992 * Bean property getter: <property>format</property>. 993 * 994 * @return The value of the <property>format</property> property on this bean, or <jk>null</jk> if it is not set. 995 */ 996 public String getFormat() { return format; } 997 998 /** 999 * Bean property getter: <property>dependentRequired</property>. 1000 * 1001 * <p> 1002 * This property was added in Draft 2019-09 as a replacement for the array form of <property>dependencies</property>. 1003 * 1004 * @return The value of the <property>dependentRequired</property> property on this bean, or <jk>null</jk> if it is not set. 1005 */ 1006 public Map<String,List<String>> getDependentRequired() { return u(dependentRequired); } 1007 1008 /** 1009 * Bean property getter: <property>dependentSchemas</property>. 1010 * 1011 * <p> 1012 * This property was added in Draft 2019-09 as a replacement for the schema form of <property>dependencies</property>. 1013 * 1014 * @return The value of the <property>dependentSchemas</property> property on this bean, or <jk>null</jk> if it is not set. 1015 */ 1016 public Map<String,JsonSchema<?>> getDependentSchemas() { return u(dependentSchemas); } 1017 1018 /** 1019 * Bean property getter: <property>description</property>. 1020 * 1021 * @return The value of the <property>description</property> property, or <jk>null</jk> if it is not set. 1022 */ 1023 public String getDescription() { return description; } 1024 1025 /** 1026 * Bean property getter: <property>else</property>. 1027 * 1028 * <p> 1029 * This property was added in Draft 07 for conditional schema application. 1030 * 1031 * @return The value of the <property>else</property> property on this bean, or <jk>null</jk> if it is not set. 1032 */ 1033 @BeanProp("else") 1034 public JsonSchema<?> getElse() { return else_; } 1035 1036 /** 1037 * Bean property getter: <property>enum</property>. 1038 * 1039 * @return The value of the <property>enum</property> property on this bean, or <jk>null</jk> if it is not set. 1040 */ 1041 public List<Object> getEnum() { return u(enum_); } 1042 1043 /** 1044 * Bean property getter: <property>examples</property>. 1045 * 1046 * <p> 1047 * This property was added in Draft 06. 1048 * 1049 * @return The value of the <property>examples</property> property on this bean, or <jk>null</jk> if it is not set. 1050 */ 1051 public List<Object> getExamples() { return u(examples); } 1052 1053 /** 1054 * Bean property getter: <property>exclusiveMaximum</property>. 1055 * 1056 * <p> 1057 * In Draft 06+, this is a numeric value representing the exclusive upper bound. 1058 * In Draft 04, this was a boolean flag. This implementation uses the Draft 06+ semantics. 1059 * 1060 * @return 1061 * The value of the <property>exclusiveMaximum</property> property on this bean, or <jk>null</jk> if it is 1062 * not set. 1063 */ 1064 public Number getExclusiveMaximum() { return exclusiveMaximum; } 1065 1066 /** 1067 * Bean property getter: <property>exclusiveMinimum</property>. 1068 * 1069 * <p> 1070 * In Draft 06+, this is a numeric value representing the exclusive lower bound. 1071 * In Draft 04, this was a boolean flag. This implementation uses the Draft 06+ semantics. 1072 * 1073 * @return 1074 * The value of the <property>exclusiveMinimum</property> property on this bean, or <jk>null</jk> if it is 1075 * not set. 1076 */ 1077 public Number getExclusiveMinimum() { return exclusiveMinimum; } 1078 1079 /** 1080 * Bean property getter: <property>id</property>. 1081 * 1082 * <p> 1083 * <b>Deprecated:</b> Use {@link #getIdUri()} instead. 1084 * This property is retained for Draft 04 backward compatibility. 1085 * 1086 * @return The value of the <property>id</property> property on this bean, or <jk>null</jk> if it is not set. 1087 * @deprecated Use {@link #getIdUri()} instead. 1088 */ 1089 @Deprecated(since = "10.0", forRemoval = true) 1090 public URI getId() { 1091 return nn(id) ? id : idUri; // Fall back to new '$id' for compatibility when reading 1092 } 1093 1094 /** 1095 * Bean property getter: <property>$id</property>. 1096 * 1097 * <p> 1098 * This is the Draft 2020-12 property for schema identification. 1099 * 1100 * @return The value of the <property>$id</property> property on this bean, or <jk>null</jk> if it is not set. 1101 */ 1102 @BeanProp("$id") 1103 public URI getIdUri() { 1104 return idUri; // Return only idUri, not id (to avoid double serialization) 1105 } 1106 1107 /** 1108 * Bean property getter: <property>if</property>. 1109 * 1110 * <p> 1111 * This property was added in Draft 07 for conditional schema application. 1112 * 1113 * @return The value of the <property>if</property> property on this bean, or <jk>null</jk> if it is not set. 1114 */ 1115 @BeanProp("if") 1116 public JsonSchema<?> getIf() { return if_; } 1117 1118 /** 1119 * Bean property getter: <property>items</property>. 1120 * 1121 * @return 1122 * The value of the <property>items</property> property on this bean, or <jk>null</jk> if it is not set. 1123 * Can be either a {@link JsonSchema} or {@link JsonSchemaArray} depending on what value was used to set it. 1124 */ 1125 @Swap(JsonSchemaOrSchemaArraySwap.class) 1126 public Object getItems() { 1127 if (nn(itemsSchema)) 1128 return itemsSchema; 1129 return itemsSchemaArray; 1130 } 1131 1132 /** 1133 * Bean property getter: <property>items</property>. 1134 * 1135 * <p> 1136 * Convenience method for returning the <property>items</property> property when it is a {@link JsonSchema} value. 1137 * 1138 * @return The currently set value, or <jk>null</jk> if the property is not set, or is set as a {@link JsonSchemaArray}. 1139 */ 1140 @BeanIgnore 1141 public JsonSchema<?> getItemsAsSchema() { return itemsSchema; } 1142 1143 /** 1144 * Bean property getter: <property>items</property>. 1145 * 1146 * <p> 1147 * Convenience method for returning the <property>items</property> property when it is a {@link JsonSchemaArray} value. 1148 * 1149 * @return The currently set value, or <jk>null</jk> if the property is not set, or is set as a {@link JsonSchema}. 1150 */ 1151 @BeanIgnore 1152 public JsonSchemaArray getItemsAsSchemaArray() { return itemsSchemaArray; } 1153 1154 /** 1155 * Bean property getter: <property>maximum</property>. 1156 * 1157 * @return The value of the <property>maximum</property> property on this bean, or <jk>null</jk> if it is not set. 1158 */ 1159 public Number getMaximum() { return maximum; } 1160 1161 /** 1162 * Bean property getter: <property>maxItems</property>. 1163 * 1164 * @return The value of the <property>maxItems</property> property on this bean, or <jk>null</jk> if it is not set. 1165 */ 1166 public Integer getMaxItems() { return maxItems; } 1167 1168 /** 1169 * Bean property getter: <property>maxLength</property>. 1170 * 1171 * @return The value of the <property>maxLength</property> property on this bean, or <jk>null</jk> if it is not set. 1172 */ 1173 public Integer getMaxLength() { return maxLength; } 1174 1175 /** 1176 * Bean property getter: <property>maxProperties</property>. 1177 * 1178 * @return 1179 * The value of the <property>maxProperties</property> property on this bean, or <jk>null</jk> if it is not set. 1180 */ 1181 public Integer getMaxProperties() { return maxProperties; } 1182 1183 /** 1184 * Bean property getter: <property>minimum</property>. 1185 * 1186 * @return The value of the <property>minimum</property> property on this bean, or <jk>null</jk> if it is not set. 1187 */ 1188 public Number getMinimum() { return minimum; } 1189 1190 /** 1191 * Bean property getter: <property>minItems</property>. 1192 * 1193 * @return The value of the <property>minItems</property> property on this bean, or <jk>null</jk> if it is not set. 1194 */ 1195 public Integer getMinItems() { return minItems; } 1196 1197 /** 1198 * Bean property getter: <property>minLength</property>. 1199 * 1200 * @return The value of the <property>minLength</property> property on this bean, or <jk>null</jk> if it is not set. 1201 */ 1202 public Integer getMinLength() { return minLength; } 1203 1204 /** 1205 * Bean property getter: <property>minProperties</property>. 1206 * 1207 * @return 1208 * The value of the <property>minProperties</property> property on this bean, or <jk>null</jk> if it is not set. 1209 */ 1210 public Integer getMinProperties() { return minProperties; } 1211 1212 /** 1213 * Bean property getter: <property>multipleOf</property>. 1214 * 1215 * @return The value of the <property>multipleOf</property> property on this bean, or <jk>null</jk> if it is not set. 1216 */ 1217 public Number getMultipleOf() { return multipleOf; } 1218 1219 /** 1220 * Bean property getter: <property>name</property>. 1221 * 1222 * <p> 1223 * This is an internal property used for tracking property names and is not part of the JSON Schema specification. 1224 * 1225 * @return The value of the <property>name</property> property on this bean, or <jk>null</jk> if it is not set. 1226 */ 1227 @BeanIgnore 1228 public String getName() { return name; } 1229 1230 /** 1231 * Bean property getter: <property>not</property>. 1232 * 1233 * @return The value of the <property>not</property> property on this bean, or <jk>null</jk> if it is not set. 1234 */ 1235 public JsonSchema<?> getNot() { return not; } 1236 1237 /** 1238 * Bean property getter: <property>oneOf</property>. 1239 * 1240 * @return The value of the <property>oneOf</property> property on this bean, or <jk>null</jk> if it is not set. 1241 */ 1242 public List<JsonSchema<?>> getOneOf() { return u(oneOf); } 1243 1244 /** 1245 * Bean property getter: <property>pattern</property>. 1246 * 1247 * @return The value of the <property>pattern</property> property on this bean, or <jk>null</jk> if it is not set. 1248 */ 1249 public String getPattern() { return pattern; } 1250 1251 /** 1252 * Bean property getter: <property>patternProperties</property>. 1253 * 1254 * @return 1255 * The value of the <property>patternProperties</property> property on this bean, or <jk>null</jk> if it is 1256 * not set. 1257 */ 1258 public Map<String,JsonSchema<?>> getPatternProperties() { return u(patternProperties); } 1259 1260 /** 1261 * Bean property getter: <property>prefixItems</property>. 1262 * 1263 * <p> 1264 * This property was added in Draft 2020-12 for tuple validation. 1265 * 1266 * @return The value of the <property>prefixItems</property> property on this bean, or <jk>null</jk> if it is not set. 1267 */ 1268 public JsonSchemaArray getPrefixItems() { return prefixItems; } 1269 1270 /** 1271 * Bean property getter: <property>properties</property>. 1272 * 1273 * @return The value of the <property>properties</property> property on this bean, or <jk>null</jk> if it is not set. 1274 */ 1275 public Map<String,JsonSchema<?>> getProperties() { return u(properties); } 1276 1277 /** 1278 * Returns the property with the specified name. 1279 * 1280 * <p> 1281 * This is equivalent to calling <property>getProperty(name, <jk>false</jk>)</property>. 1282 * 1283 * @param name The property name. Can be <jk>null</jk> (no property has a <jk>null</jk> name, so <jk>null</jk> is returned). 1284 * @return The property with the specified name, or <jk>null</jk> if no property is specified. 1285 */ 1286 public JsonSchema<?> getProperty(String name) { 1287 return getProperty(name, false); 1288 } 1289 1290 /** 1291 * Returns the property with the specified name. 1292 * 1293 * <p> 1294 * If <property>resolve</property> is <jk>true</jk>, the property object will automatically be resolved by calling 1295 * {@link #resolve()}. 1296 * Therefore, <property>getProperty(name, <jk>true</jk>)</property> is equivalent to calling 1297 * <property>getProperty(name).resolve()</property>, except it's safe from a potential 1298 * <property>NullPointerException</property>. 1299 * 1300 * @param name The property name. Can be <jk>null</jk> (no property has a <jk>null</jk> name, so <jk>null</jk> is returned). 1301 * @param resolve If <jk>true</jk>, calls {@link #resolve()} on object before returning. 1302 * @return The property with the specified name, or <jk>null</jk> if no property is specified. 1303 */ 1304 public JsonSchema<?> getProperty(String name, boolean resolve) { 1305 if (properties == null) 1306 return null; 1307 var s = properties.get(name); 1308 if (s == null) 1309 return null; 1310 if (resolve) 1311 s = s.resolve(); 1312 return s; 1313 } 1314 1315 /** 1316 * Bean property getter: <property>readOnly</property>. 1317 * 1318 * <p> 1319 * This property was added in Draft 07. 1320 * 1321 * @return The value of the <property>readOnly</property> property on this bean, or <jk>null</jk> if it is not set. 1322 */ 1323 public Boolean getReadOnly() { return readOnly; } 1324 1325 /** 1326 * Bean property getter: <property>$ref</property>. 1327 * 1328 * @return The value of the <property>$ref</property> property on this bean, or <jk>null</jk> if it is not set. 1329 */ 1330 @BeanProp("$ref") 1331 public URI getRef() { return ref; } 1332 1333 /** 1334 * Bean property getter: <property>required</property>. 1335 * 1336 * @return The value of the <property>required</property> property on this bean, or <jk>null</jk> if it is not set. 1337 */ 1338 public List<String> getRequired() { return u(required); } 1339 1340 /** 1341 * Bean property getter: <property>$schema</property>. 1342 * 1343 * @return The value of the <property>$schema</property> property on this bean, or <jk>null</jk> if it is not set. 1344 */ 1345 @BeanProp("$schema") 1346 public URI getSchemaVersionUri() { return schemaVersion; } 1347 1348 /** 1349 * Bean property getter: <property>then</property>. 1350 * 1351 * <p> 1352 * This property was added in Draft 07 for conditional schema application. 1353 * 1354 * @return The value of the <property>then</property> property on this bean, or <jk>null</jk> if it is not set. 1355 */ 1356 @BeanProp("then") 1357 public JsonSchema<?> getThen() { return then_; } 1358 1359 /** 1360 * Bean property getter: <property>summary</property>. 1361 * 1362 * <p> 1363 * A short, concise summary of the schema's purpose, intended for AI/LLM consumption, compact 1364 * documentation, or any context where brevity is important. Unlike {@link #getDescription()}, 1365 * which can be multi-line and detailed, this value should be a single sentence or phrase. 1366 * 1367 * <p> 1368 * This is a Juneau extension. It serializes as the JSON Schema keyword <c>"summary"</c>. 1369 * 1370 * @return The value of the <property>summary</property> property, or <jk>null</jk> if it is not set. 1371 * @since 10.0.0 1372 */ 1373 public String getSummary() { return summary; } 1374 1375 /** 1376 * Bean property getter: <property>title</property>. 1377 * 1378 * @return The value of the <property>title</property> property, or <jk>null</jk> if it is not set. 1379 */ 1380 public String getTitle() { return title; } 1381 1382 /** 1383 * Bean property getter: <property>type</property>. 1384 * 1385 * @return 1386 * The value of the <property>type</property> property on this bean, or <jk>null</jk> if it is not set. 1387 * Can be either a {@link JsonType} or {@link JsonTypeArray} depending on what value was used to set it. 1388 */ 1389 @Swap(JsonTypeOrJsonTypeArraySwap.class) 1390 public Object getType() { 1391 if (nn(typeJsonType)) 1392 return typeJsonType; 1393 return typeJsonTypeArray; 1394 } 1395 1396 /** 1397 * Bean property getter: <property>type</property>. 1398 * 1399 * <p> 1400 * Convenience method for returning the <property>type</property> property when it is a {@link JsonType} value. 1401 * 1402 * @return 1403 * The currently set value, or <jk>null</jk> if the property is not set, or is set as a {@link JsonTypeArray}. 1404 */ 1405 @BeanIgnore 1406 public JsonType getTypeAsJsonType() { return typeJsonType; } 1407 1408 /** 1409 * Bean property getter: <property>type</property>. 1410 * 1411 * <p> 1412 * Convenience method for returning the <property>type</property> property when it is a {@link JsonTypeArray} value. 1413 * 1414 * @return The currently set value, or <jk>null</jk> if the property is not set, or is set as a {@link JsonType}. 1415 */ 1416 @BeanIgnore 1417 public JsonTypeArray getTypeAsJsonTypeArray() { return typeJsonTypeArray; } 1418 1419 /** 1420 * Bean property getter: <property>unevaluatedItems</property>. 1421 * 1422 * <p> 1423 * This property was added in Draft 2019-09. 1424 * 1425 * @return The value of the <property>unevaluatedItems</property> property on this bean, or <jk>null</jk> if it is not set. 1426 */ 1427 public JsonSchema<?> getUnevaluatedItems() { return unevaluatedItems; } 1428 1429 /** 1430 * Bean property getter: <property>unevaluatedProperties</property>. 1431 * 1432 * <p> 1433 * This property was added in Draft 2019-09. 1434 * 1435 * @return The value of the <property>unevaluatedProperties</property> property on this bean, or <jk>null</jk> if it is not set. 1436 */ 1437 public JsonSchema<?> getUnevaluatedProperties() { return unevaluatedProperties; } 1438 1439 /** 1440 * Bean property getter: <property>uniqueItems</property>. 1441 * 1442 * @return 1443 * The value of the <property>uniqueItems</property> property on this bean, or <jk>null</jk> if it is not set. 1444 */ 1445 public Boolean getUniqueItems() { return uniqueItems; } 1446 1447 /** 1448 * Bean property getter: <property>writeOnly</property>. 1449 * 1450 * <p> 1451 * This property was added in Draft 07. 1452 * 1453 * @return The value of the <property>writeOnly</property> property on this bean, or <jk>null</jk> if it is not set. 1454 */ 1455 public Boolean getWriteOnly() { return writeOnly; } 1456 1457 /** 1458 * Resolve schema if reference. 1459 * 1460 * <p> 1461 * If this schema is a reference to another schema (has its <property>$ref</property> property set), this 1462 * method will retrieve the referenced schema from the schema map registered with this schema. 1463 * 1464 * <p> 1465 * If this schema is not a reference, or no schema map is registered with this schema, this method is a no-op and 1466 * simply returns this object. 1467 * 1468 * @return The referenced schema, or <jk>null</jk> if this schema is a <property>$ref</property> whose target is not found in the registered schema map. 1469 */ 1470 public JsonSchema<?> resolve() { 1471 if (ref == null || master.schemaMap == null) 1472 return this; 1473 return master.schemaMap.get(ref); 1474 } 1475 1476 /** 1477 * Bean property setter: <property>additionalItems</property>. 1478 * 1479 * @param value 1480 * The new value for the <property>additionalItems</property> property on this bean. 1481 * This object must be of type {@link Boolean} or {@link JsonSchemaArray}. 1482 * <br>Can be <jk>null</jk> to unset the property. 1483 * @return This object. 1484 * @throws BeanRuntimeException If invalid object type passed in. 1485 */ 1486 public SELF setAdditionalItems(Object value) { 1487 this.additionalItemsBoolean = null; 1488 this.additionalItemsSchemaArray = null; 1489 if (nn(value)) { 1490 if (value instanceof Boolean value2) 1491 this.additionalItemsBoolean = value2; 1492 else if (value instanceof JsonSchemaArray value2) { 1493 this.additionalItemsSchemaArray = value2; 1494 setMasterOn(this.additionalItemsSchemaArray); 1495 } else { 1496 throw brex(JsonSchemaProperty.class, "Invalid attribute type '%s' passed in. Must be one of the following: Boolean, JsonSchemaArray", cn(value)); 1497 } 1498 } 1499 return self(); 1500 } 1501 1502 /** 1503 * Bean property setter: <property>additionalProperties</property>. 1504 * 1505 * @param value 1506 * The new value for the <property>additionalProperties</property> property on this bean. 1507 * This object must be of type {@link Boolean} or {@link JsonSchema}. 1508 * <br>Can be <jk>null</jk> to unset the property. 1509 * @return This object. 1510 * @throws BeanRuntimeException If invalid object type passed in. 1511 */ 1512 @MarshalledProp(dictionary={ JsonSchema.class }) 1513 public SELF setAdditionalProperties(Object value) { 1514 this.additionalPropertiesBoolean = null; 1515 this.additionalPropertiesSchema = null; 1516 if (nn(value)) { 1517 if (value instanceof Boolean value2) 1518 this.additionalPropertiesBoolean = value2; 1519 else if (value instanceof JsonSchema<?> value2) { 1520 this.additionalPropertiesSchema = value2; 1521 setMasterOn(this.additionalPropertiesSchema); 1522 } else 1523 throw brex(JsonSchemaProperty.class, "Invalid attribute type '%s' passed in. Must be one of the following: Boolean, JsonSchema", cn(value)); 1524 } 1525 return self(); 1526 } 1527 1528 /** 1529 * Bean property setter: <property>allOf</property>. 1530 * 1531 * @param value The new value for the <property>allOf</property> property on this bean. 1532 * @return This object. 1533 */ 1534 public SELF setAllOf(List<JsonSchema<?>> value) { 1535 this.allOf = value; 1536 setMasterOn(value); 1537 return self(); 1538 } 1539 1540 /** 1541 * Bean property setter: <property>allOf</property>. 1542 * 1543 * @param value The new value for the <property>allOf</property> property on this bean. 1544 * @return This object. 1545 */ 1546 public SELF setAllOf(JsonSchema<?>...value) { 1547 return setAllOf(list(value)); 1548 } 1549 1550 /** 1551 * Bean property setter: <property>anyOf</property>. 1552 * 1553 * @param value The new value of the <property>anyOf</property> property on this bean. 1554 * @return This object. 1555 */ 1556 public SELF setAnyOf(List<JsonSchema<?>> value) { 1557 this.anyOf = value; 1558 setMasterOn(value); 1559 return self(); 1560 } 1561 1562 /** 1563 * Bean property setter: <property>anyOf</property>. 1564 * 1565 * @param value The new value for the <property>anyOf</property> property on this bean. 1566 * @return This object. 1567 */ 1568 public SELF setAnyOf(JsonSchema<?>...value) { 1569 return setAnyOf(list(value)); 1570 } 1571 1572 /** 1573 * Bean property setter: <property>const</property>. 1574 * 1575 * <p> 1576 * This property was added in Draft 06. 1577 * 1578 * @param value The new value for the <property>const</property> property on this bean. 1579 * @return This object. 1580 */ 1581 public SELF setConst(Object value) { 1582 this.const_ = value; 1583 return self(); 1584 } 1585 1586 /** 1587 * Bean property setter: <property>contentEncoding</property>. 1588 * 1589 * <p> 1590 * This property was added in Draft 07. 1591 * 1592 * @param value The new value for the <property>contentEncoding</property> property on this bean. 1593 * @return This object. 1594 */ 1595 public SELF setContentEncoding(String value) { 1596 this.contentEncoding = value; 1597 return self(); 1598 } 1599 1600 /** 1601 * Bean property setter: <property>contentMediaType</property>. 1602 * 1603 * <p> 1604 * This property was added in Draft 07. 1605 * 1606 * @param value The new value for the <property>contentMediaType</property> property on this bean. 1607 * @return This object. 1608 */ 1609 public SELF setContentMediaType(String value) { 1610 this.contentMediaType = value; 1611 return self(); 1612 } 1613 1614 /** 1615 * Bean property setter: <property>deprecated</property>. 1616 * 1617 * <p> 1618 * This property was added in Draft 2019-09. 1619 * 1620 * @param value The new value for the <property>deprecated</property> property on this bean. 1621 * @return This object. 1622 */ 1623 public SELF setDeprecated(Boolean value) { 1624 this.deprecated = value; 1625 return self(); 1626 } 1627 1628 /** 1629 * Bean property setter: <property>$comment</property>. 1630 * 1631 * <p> 1632 * This property was added in Draft 07. 1633 * 1634 * @param value The new value for the <property>$comment</property> property on this bean. 1635 * @return This object. 1636 */ 1637 @BeanProp("$comment") 1638 public SELF setComment(String value) { 1639 this.comment = value; 1640 return self(); 1641 } 1642 1643 /** 1644 * Bean property setter: <property>definitions</property>. 1645 * 1646 * @param value The new value for the <property>definitions</property> property on this bean. 1647 * @return This object. 1648 */ 1649 public SELF setDefinitions(Map<String,JsonSchema<?>> value) { 1650 this.definitions = value; 1651 if (nn(value)) 1652 setMasterOn(value.values()); 1653 return self(); 1654 } 1655 1656 /** 1657 * Bean property setter: <property>$defs</property>. 1658 * 1659 * <p> 1660 * This is the Draft 2020-12 replacement for <property>definitions</property>. 1661 * Both properties are supported for backward compatibility. 1662 * 1663 * @param value The new value for the <property>$defs</property> property on this bean. 1664 * @return This object. 1665 */ 1666 @BeanProp("$defs") 1667 public SELF setDefs(Map<String,JsonSchema<?>> value) { 1668 this.defs = value; 1669 if (nn(value)) 1670 setMasterOn(value.values()); 1671 return self(); 1672 } 1673 1674 /** 1675 * Bean property setter: <property>dependencies</property>. 1676 * 1677 * @param value The new value for the <property>dependencies</property> property on this bean. 1678 * @return This object. 1679 */ 1680 public SELF setDependencies(Map<String,JsonSchema<?>> value) { 1681 this.dependencies = value; 1682 if (nn(value)) 1683 setMasterOn(value.values()); 1684 return self(); 1685 } 1686 1687 /** 1688 * Bean property setter: <property>format</property>. 1689 * 1690 * @param value The new value for the <property>format</property> property on this bean. 1691 * @return This object. 1692 */ 1693 public SELF setFormat(String value) { 1694 this.format = value; 1695 return self(); 1696 } 1697 1698 /** 1699 * Bean property setter: <property>dependentRequired</property>. 1700 * 1701 * <p> 1702 * This property was added in Draft 2019-09 as a replacement for the array form of <property>dependencies</property>. 1703 * 1704 * @param value The new value for the <property>dependentRequired</property> property on this bean. 1705 * @return This object. 1706 */ 1707 public SELF setDependentRequired(Map<String,List<String>> value) { 1708 this.dependentRequired = value; 1709 return self(); 1710 } 1711 1712 /** 1713 * Bean property setter: <property>dependentSchemas</property>. 1714 * 1715 * <p> 1716 * This property was added in Draft 2019-09 as a replacement for the schema form of <property>dependencies</property>. 1717 * 1718 * @param value The new value for the <property>dependentSchemas</property> property on this bean. 1719 * @return This object. 1720 */ 1721 public SELF setDependentSchemas(Map<String,JsonSchema<?>> value) { 1722 this.dependentSchemas = value; 1723 if (nn(value)) 1724 setMasterOn(value.values()); 1725 return self(); 1726 } 1727 1728 /** 1729 * Bean property setter: <property>description</property>. 1730 * 1731 * @param value The new value for the <property>description</property> property on this bean. 1732 * @return This object. 1733 */ 1734 public SELF setDescription(String value) { 1735 this.description = value; 1736 return self(); 1737 } 1738 1739 /** 1740 * Bean property setter: <property>else</property>. 1741 * 1742 * <p> 1743 * This property was added in Draft 07 for conditional schema application. 1744 * 1745 * @param value The new value for the <property>else</property> property on this bean. 1746 * @return This object. 1747 */ 1748 @BeanProp("else") 1749 public SELF setElse(JsonSchema<?> value) { 1750 this.else_ = value; 1751 setMasterOn(value); 1752 return self(); 1753 } 1754 1755 /** 1756 * Bean property setter: <property>enum</property>. 1757 * 1758 * @param value The new value for the <property>enum</property> property on this bean. 1759 * @return This object. 1760 */ 1761 public SELF setEnum(List<Object> value) { 1762 this.enum_ = value; 1763 return self(); 1764 } 1765 1766 /** 1767 * Bean property setter: <property>enum</property>. 1768 * 1769 * @param value The new value for the <property>enum</property> property on this bean. 1770 * @return This object. 1771 */ 1772 public SELF setEnum(Object...value) { 1773 return setEnum(list(value)); 1774 } 1775 1776 /** 1777 * Bean property setter: <property>examples</property>. 1778 * 1779 * <p> 1780 * This property was added in Draft 06. 1781 * 1782 * @param value The new value for the <property>examples</property> property on this bean. 1783 * @return This object. 1784 */ 1785 public SELF setExamples(List<Object> value) { 1786 this.examples = value; 1787 return self(); 1788 } 1789 1790 /** 1791 * Bean property setter: <property>examples</property>. 1792 * 1793 * <p> 1794 * This property was added in Draft 06. 1795 * 1796 * @param value The new value for the <property>examples</property> property on this bean. 1797 * @return This object. 1798 */ 1799 public SELF setExamples(Object...value) { 1800 return setExamples(list(value)); 1801 } 1802 1803 /** 1804 * Bean property setter: <property>exclusiveMaximum</property>. 1805 * 1806 * <p> 1807 * In Draft 06+, this is a numeric value representing the exclusive upper bound. 1808 * In Draft 04, this was a boolean flag. This implementation uses the Draft 06+ semantics. 1809 * 1810 * @param value The new value for the <property>exclusiveMaximum</property> property on this bean. 1811 * @return This object. 1812 */ 1813 public SELF setExclusiveMaximum(Number value) { 1814 this.exclusiveMaximum = value; 1815 return self(); 1816 } 1817 1818 /** 1819 * Bean property setter: <property>exclusiveMinimum</property>. 1820 * 1821 * <p> 1822 * In Draft 06+, this is a numeric value representing the exclusive lower bound. 1823 * In Draft 04, this was a boolean flag. This implementation uses the Draft 06+ semantics. 1824 * 1825 * @param value The new value for the <property>exclusiveMinimum</property> property on this bean. 1826 * @return This object. 1827 */ 1828 public SELF setExclusiveMinimum(Number value) { 1829 this.exclusiveMinimum = value; 1830 return self(); 1831 } 1832 1833 /** 1834 * Bean property setter: <property>id</property>. 1835 * 1836 * <p> 1837 * <b>Deprecated:</b> Use {@link #setIdUri(Object)} instead. 1838 * This property is retained for Draft 04 backward compatibility. 1839 * 1840 * <p> 1841 * The value can be of any of the following types: {@link URI}, {@link URL}, {@link String}. 1842 * Strings must be valid URIs. 1843 * 1844 * <p> 1845 * URIs defined by {@link UriResolver} can be used for values. 1846 * 1847 * @param value The new value for the <property>id</property> property on this bean. Can be <jk>null</jk> to unset the property. 1848 * @return This object. 1849 * @deprecated Use {@link #setIdUri(Object)} instead. 1850 */ 1851 @Deprecated(since = "10.0", forRemoval = true) 1852 public SELF setId(Object value) { 1853 this.id = toUri(value); 1854 return self(); 1855 } 1856 1857 /** 1858 * Bean property setter: <property>$id</property>. 1859 * 1860 * <p> 1861 * This is the Draft 2020-12 property for schema identification. 1862 * 1863 * <p> 1864 * The value can be of any of the following types: {@link URI}, {@link URL}, {@link String}. 1865 * Strings must be valid URIs. 1866 * 1867 * <p> 1868 * URIs defined by {@link UriResolver} can be used for values. 1869 * 1870 * @param value The new value for the <property>$id</property> property on this bean. Can be <jk>null</jk> to unset the property. 1871 * @return This object. 1872 */ 1873 @BeanProp("$id") 1874 public SELF setIdUri(Object value) { 1875 this.idUri = toUri(value); 1876 return self(); 1877 } 1878 1879 /** 1880 * Bean property setter: <property>if</property>. 1881 * 1882 * <p> 1883 * This property was added in Draft 07 for conditional schema application. 1884 * 1885 * @param value The new value for the <property>if</property> property on this bean. 1886 * @return This object. 1887 */ 1888 @BeanProp("if") 1889 public SELF setIf(JsonSchema<?> value) { 1890 this.if_ = value; 1891 setMasterOn(value); 1892 return self(); 1893 } 1894 1895 /** 1896 * Bean property setter: <property>items</property>. 1897 * 1898 * @param value 1899 * The new value for the <property>items</property> property on this bean. 1900 * This object must be of type {@link JsonSchema} or {@link JsonSchemaArray}. 1901 * <br>Can be <jk>null</jk> to unset the property. 1902 * @return This object. 1903 * @throws BeanRuntimeException If invalid object type passed in. 1904 */ 1905 public SELF setItems(Object value) { 1906 this.itemsSchema = null; 1907 this.itemsSchemaArray = null; 1908 if (nn(value)) { 1909 if (value instanceof JsonSchema<?> value2) { 1910 this.itemsSchema = value2; 1911 setMasterOn(this.itemsSchema); 1912 } else if (value instanceof JsonSchemaArray value2) { 1913 this.itemsSchemaArray = value2; 1914 setMasterOn(this.itemsSchemaArray); 1915 } else { 1916 throw brex(JsonSchemaProperty.class, "Invalid attribute type '%s' passed in. Must be one of the following: JsonSchema, JsonSchemaArray", cn(value)); 1917 } 1918 } 1919 return self(); 1920 } 1921 1922 /** 1923 * Bean property setter: <property>maximum</property>. 1924 * 1925 * @param value The new value for the <property>maximum</property> property on this bean. 1926 * @return This object. 1927 */ 1928 public SELF setMaximum(Number value) { 1929 this.maximum = value; 1930 return self(); 1931 } 1932 1933 /** 1934 * Bean property setter: <property>maxItems</property>. 1935 * 1936 * @param value The new value for the <property>maxItems</property> property on this bean. 1937 * @return This object. 1938 */ 1939 public SELF setMaxItems(Integer value) { 1940 this.maxItems = value; 1941 return self(); 1942 } 1943 1944 /** 1945 * Bean property setter: <property>maxLength</property>. 1946 * 1947 * @param value The new value for the <property>maxLength</property> property on this bean. 1948 * @return This object. 1949 */ 1950 public SELF setMaxLength(Integer value) { 1951 this.maxLength = value; 1952 return self(); 1953 } 1954 1955 /** 1956 * Bean property setter: <property>maxProperties</property>. 1957 * 1958 * @param value The new value for the <property>maxProperties</property> property on this bean. 1959 * @return This object. 1960 */ 1961 public SELF setMaxProperties(Integer value) { 1962 this.maxProperties = value; 1963 return self(); 1964 } 1965 1966 /** 1967 * Bean property setter: <property>minimum</property>. 1968 * 1969 * @param value The new value for the <property>minimum</property> property on this bean. 1970 * @return This object. 1971 */ 1972 public SELF setMinimum(Number value) { 1973 this.minimum = value; 1974 return self(); 1975 } 1976 1977 /** 1978 * Bean property setter: <property>minItems</property>. 1979 * 1980 * @param value The new value for the <property>minItems</property> property on this bean. 1981 * @return This object. 1982 */ 1983 public SELF setMinItems(Integer value) { 1984 this.minItems = value; 1985 return self(); 1986 } 1987 1988 /** 1989 * Bean property setter: <property>minLength</property>. 1990 * 1991 * @param value The new value for the <property>minLength</property> property on this bean. 1992 * @return This object. 1993 */ 1994 public SELF setMinLength(Integer value) { 1995 this.minLength = value; 1996 return self(); 1997 } 1998 1999 /** 2000 * Bean property setter: <property>minProperties</property>. 2001 * 2002 * @param value The new value for the <property>minProperties</property> property on this bean. 2003 * @return This object. 2004 */ 2005 public SELF setMinProperties(Integer value) { 2006 this.minProperties = value; 2007 return self(); 2008 } 2009 2010 /** 2011 * Bean property setter: <property>multipleOf</property>. 2012 * 2013 * @param value The new value for the <property>multipleOf</property> property on this bean. 2014 * @return This object. 2015 */ 2016 public SELF setMultipleOf(Number value) { 2017 this.multipleOf = value; 2018 return self(); 2019 } 2020 2021 /** 2022 * Bean property setter: <property>name</property>. 2023 * 2024 * <p> 2025 * This is an internal property used for tracking property names and is not part of the JSON Schema specification. 2026 * 2027 * @param value The new value for the <property>name</property> property on this bean. 2028 * @return This object. 2029 */ 2030 @BeanIgnore 2031 public SELF setName(String value) { 2032 this.name = value; 2033 return self(); 2034 } 2035 2036 /** 2037 * Bean property setter: <property>not</property>. 2038 * 2039 * @param value The new value for the <property>not</property> property on this bean. 2040 * @return This object. 2041 */ 2042 public SELF setNot(JsonSchema<?> value) { 2043 this.not = value; 2044 setMasterOn(value); 2045 return self(); 2046 } 2047 2048 /** 2049 * Bean property setter: <property>oneOf</property>. 2050 * 2051 * @param value The new value for the <property>oneOf</property> property on this bean. 2052 * @return This object. 2053 */ 2054 public SELF setOneOf(List<JsonSchema<?>> value) { 2055 this.oneOf = value; 2056 setMasterOn(value); 2057 return self(); 2058 } 2059 2060 /** 2061 * Bean property setter: <property>oneOf</property>. 2062 * 2063 * @param value The new value for the <property>oneOf</property> property on this bean. 2064 * @return This object. 2065 */ 2066 public SELF setOneOf(JsonSchema<?>...value) { 2067 return setOneOf(list(value)); 2068 } 2069 2070 /** 2071 * Bean property setter: <property>pattern</property>. 2072 * 2073 * @param value The new value for the <property>pattern</property> property on this bean. 2074 * @return This object. 2075 */ 2076 public SELF setPattern(String value) { 2077 this.pattern = value; 2078 return self(); 2079 } 2080 2081 /** 2082 * Bean property setter: <property>patternProperties</property>. 2083 * 2084 * @param value The new value for the <property>patternProperties</property> property on this bean. 2085 * @return This object. 2086 */ 2087 public SELF setPatternProperties(Map<String,JsonSchema<?>> value) { 2088 this.patternProperties = value; 2089 if (nn(value)) { 2090 value.entrySet().forEach(x -> { 2091 var s = x.getValue(); 2092 setMasterOn(s); 2093 s.setName(x.getKey()); 2094 }); 2095 } 2096 return self(); 2097 } 2098 2099 /** 2100 * Bean property setter: <property>prefixItems</property>. 2101 * 2102 * <p> 2103 * This property was added in Draft 2020-12 for tuple validation. 2104 * 2105 * @param value The new value for the <property>prefixItems</property> property on this bean. 2106 * @return This object. 2107 */ 2108 public SELF setPrefixItems(JsonSchemaArray value) { 2109 this.prefixItems = value; 2110 setMasterOn(value); 2111 return self(); 2112 } 2113 2114 /** 2115 * Bean property setter: <property>properties</property>. 2116 * 2117 * @param value The new value for the <property>properties</property> property on this bean. 2118 * @return This object. 2119 */ 2120 public SELF setProperties(Map<String,JsonSchema<?>> value) { 2121 this.properties = value; 2122 if (nn(value)) { 2123 value.entrySet().forEach(x -> { 2124 var v = x.getValue(); 2125 setMasterOn(v); 2126 v.setName(x.getKey()); 2127 }); 2128 } 2129 return self(); 2130 } 2131 2132 /** 2133 * Bean property setter: <property>readOnly</property>. 2134 * 2135 * <p> 2136 * This property was added in Draft 07. 2137 * 2138 * @param value The new value for the <property>readOnly</property> property on this bean. 2139 * @return This object. 2140 */ 2141 public SELF setReadOnly(Boolean value) { 2142 this.readOnly = value; 2143 return self(); 2144 } 2145 2146 /** 2147 * Bean property setter: <property>$ref</property>. 2148 * 2149 * <p> 2150 * The value can be of any of the following types: {@link URI}, {@link URL}, {@link String}. 2151 * Strings must be valid URIs. 2152 * 2153 * <p> 2154 * URIs defined by {@link UriResolver} can be used for values. 2155 * 2156 * @param value The new value for the <property>$ref</property> property on this bean. Can be <jk>null</jk> to unset the property. 2157 * @return This object. 2158 */ 2159 @BeanProp("$ref") 2160 public SELF setRef(Object value) { 2161 this.ref = toUri(value); 2162 return self(); 2163 } 2164 2165 /** 2166 * Bean property setter: <property>required</property>. 2167 * 2168 * @param value The new value for the <property>required</property> property on this bean. 2169 * @return This object. 2170 */ 2171 public SELF setRequired(List<String> value) { 2172 this.required = value; 2173 return self(); 2174 } 2175 2176 /** 2177 * Bean property setter: <property>required</property>. 2178 * 2179 * @param value The new value for the <property>required</property> property on this bean. 2180 * @return This object. 2181 */ 2182 public SELF setRequired(String...value) { 2183 return setRequired(list(value)); 2184 } 2185 2186 /** 2187 * Associates a schema map with this schema for resolving other schemas identified through <property>$ref</property> 2188 * properties. 2189 * 2190 * @param value The schema map to associate with this schema. Can be <jk>null</jk> to unset the property. 2191 * @return This object. 2192 */ 2193 @BeanIgnore 2194 public SELF setSchemaMap(JsonSchemaMap value) { 2195 this.schemaMap = value; 2196 return self(); 2197 } 2198 2199 /** 2200 * Bean property setter: <property>$schema</property>. 2201 * 2202 * <p> 2203 * The value can be of any of the following types: {@link URI}, {@link URL}, {@link String}. 2204 * Strings must be valid URIs. 2205 * 2206 * <p> 2207 * URIs defined by {@link UriResolver} can be used for values. 2208 * 2209 * @param value The new value for the <property>schemaVersion</property> property on this bean. Can be <jk>null</jk> to unset the property. 2210 * @return This object. 2211 */ 2212 @BeanProp("$schema") 2213 public SELF setSchemaVersionUri(Object value) { 2214 this.schemaVersion = toUri(value); 2215 return self(); 2216 } 2217 2218 /** 2219 * Bean property setter: <property>then</property>. 2220 * 2221 * <p> 2222 * This property was added in Draft 07 for conditional schema application. 2223 * 2224 * @param value The new value for the <property>then</property> property on this bean. 2225 * @return This object. 2226 */ 2227 @BeanProp("then") 2228 public SELF setThen(JsonSchema<?> value) { 2229 this.then_ = value; 2230 setMasterOn(value); 2231 return self(); 2232 } 2233 2234 /** 2235 * Bean property setter: <property>summary</property>. 2236 * 2237 * @param value The new value for the <property>summary</property> property on this bean. 2238 * @return This object. 2239 * @since 10.0.0 2240 */ 2241 public SELF setSummary(String value) { 2242 this.summary = value; 2243 return self(); 2244 } 2245 2246 /** 2247 * Bean property setter: <property>title</property>. 2248 * 2249 * @param value The new value for the <property>title</property> property on this bean. 2250 * @return This object. 2251 */ 2252 public SELF setTitle(String value) { 2253 this.title = value; 2254 return self(); 2255 } 2256 2257 /** 2258 * Bean property setter: <property>type</property>. 2259 * 2260 * @param value 2261 * The new value for the <property>type</property> property on this bean. 2262 * This object must be of type {@link JsonType} or {@link JsonTypeArray}. 2263 * <br>Can be <jk>null</jk> to unset the property. 2264 * @return This object. 2265 * @throws BeanRuntimeException If invalid object type passed in. 2266 */ 2267 public SELF setType(Object value) { 2268 this.typeJsonType = null; 2269 this.typeJsonTypeArray = null; 2270 if (nn(value)) { 2271 if (value instanceof JsonType value2) 2272 this.typeJsonType = value2; 2273 else if (value instanceof JsonTypeArray value2) 2274 this.typeJsonTypeArray = value2; 2275 else 2276 throw brex(JsonSchemaProperty.class, "Invalid attribute type '%s' passed in. Must be one of the following: SimpleType, SimpleTypeArray", cn(value)); 2277 } 2278 return self(); 2279 } 2280 2281 /** 2282 * Bean property setter: <property>unevaluatedItems</property>. 2283 * 2284 * <p> 2285 * This property was added in Draft 2019-09. 2286 * 2287 * @param value The new value for the <property>unevaluatedItems</property> property on this bean. 2288 * @return This object. 2289 */ 2290 public SELF setUnevaluatedItems(JsonSchema<?> value) { 2291 this.unevaluatedItems = value; 2292 setMasterOn(value); 2293 return self(); 2294 } 2295 2296 /** 2297 * Bean property setter: <property>unevaluatedProperties</property>. 2298 * 2299 * <p> 2300 * This property was added in Draft 2019-09. 2301 * 2302 * @param value The new value for the <property>unevaluatedProperties</property> property on this bean. 2303 * @return This object. 2304 */ 2305 public SELF setUnevaluatedProperties(JsonSchema<?> value) { 2306 this.unevaluatedProperties = value; 2307 setMasterOn(value); 2308 return self(); 2309 } 2310 2311 /** 2312 * Bean property setter: <property>uniqueItems</property>. 2313 * 2314 * @param value The new value for the <property>uniqueItems</property> property on this bean. 2315 * @return This object. 2316 */ 2317 public SELF setUniqueItems(Boolean value) { 2318 this.uniqueItems = value; 2319 return self(); 2320 } 2321 2322 /** 2323 * Bean property setter: <property>writeOnly</property>. 2324 * 2325 * <p> 2326 * This property was added in Draft 07. 2327 * 2328 * @param value The new value for the <property>writeOnly</property> property on this bean. 2329 * @return This object. 2330 */ 2331 public SELF setWriteOnly(Boolean value) { 2332 this.writeOnly = value; 2333 return self(); 2334 } 2335 2336 @Override /* Overridden from Object */ 2337 public String toString() { 2338 return Json.of(this); 2339 } 2340 2341 private void setMasterOn(Collection<JsonSchema<?>> ss) { 2342 if (nn(ss)) 2343 ss.forEach(this::setMasterOn); 2344 } 2345 2346 private void setMasterOn(JsonSchema<?> s) { 2347 if (nn(s)) 2348 s.setMaster(this); 2349 } 2350 2351 private void setMasterOn(JsonSchema<?>[] ss) { 2352 reqnn("ss", ss); 2353 for (var s : ss) 2354 setMasterOn(s); 2355 } 2356 2357 private void setMasterOn(JsonSchemaArray ss) { 2358 if (nn(ss)) 2359 ss.forEach(this::setMasterOn); 2360 } 2361 2362 /** 2363 * Sets the master schema for this schema and all child schema objects. 2364 * 2365 * <p> 2366 * All child elements in a schema should point to a single "master" schema in order to locate registered JsonSchemaMap 2367 * objects for resolving external schemas. 2368 * 2369 * @param master The master schema to associate on this and all children. Can be <jk>null</jk> to clear the master reference on this schema and all children. 2370 */ 2371 @SuppressWarnings({ 2372 "java:S3776" // Cognitive complexity acceptable for this logic 2373 }) 2374 protected void setMaster(JsonSchema<?> master) { 2375 this.master = master; 2376 if (nn(definitions)) 2377 definitions.values().forEach(x -> x.setMaster(master)); 2378 if (nn(defs)) 2379 defs.values().forEach(x -> x.setMaster(master)); 2380 if (nn(properties)) 2381 properties.values().forEach(x -> x.setMaster(master)); 2382 if (nn(patternProperties)) 2383 patternProperties.values().forEach(x -> x.setMaster(master)); 2384 if (nn(dependencies)) 2385 dependencies.values().forEach(x -> x.setMaster(master)); 2386 if (nn(dependentSchemas)) 2387 dependentSchemas.values().forEach(x -> x.setMaster(master)); 2388 if (nn(itemsSchema)) 2389 itemsSchema.setMaster(master); 2390 if (nn(itemsSchemaArray)) 2391 itemsSchemaArray.forEach(x -> x.setMaster(master)); 2392 if (nn(prefixItems)) 2393 prefixItems.forEach(x -> x.setMaster(master)); 2394 if (nn(additionalItemsSchemaArray)) 2395 additionalItemsSchemaArray.forEach(x -> x.setMaster(master)); 2396 if (nn(unevaluatedItems)) 2397 unevaluatedItems.setMaster(master); 2398 if (nn(additionalPropertiesSchema)) 2399 additionalPropertiesSchema.setMaster(master); 2400 if (nn(unevaluatedProperties)) 2401 unevaluatedProperties.setMaster(master); 2402 if (nn(allOf)) 2403 allOf.forEach(x -> x.setMaster(master)); 2404 if (nn(anyOf)) 2405 anyOf.forEach(x -> x.setMaster(master)); 2406 if (nn(oneOf)) 2407 oneOf.forEach(x -> x.setMaster(master)); 2408 if (nn(not)) 2409 not.setMaster(master); 2410 if (nn(if_)) 2411 if_.setMaster(master); 2412 if (nn(then_)) 2413 then_.setMaster(master); 2414 if (nn(else_)) 2415 else_.setMaster(master); 2416 } 2417}