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