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.openapi3; 018 019import static org.apache.juneau.commons.utils.AssertionUtils.*; 020import static org.apache.juneau.commons.utils.CollectionUtils.*; 021import static org.apache.juneau.commons.utils.StringUtils.*; 022import static org.apache.juneau.commons.utils.ThrowableUtils.*; 023import static org.apache.juneau.commons.utils.Utils.*; 024import static org.apache.juneau.internal.ConverterUtils.*; 025 026import java.util.*; 027 028import org.apache.juneau.annotation.*; 029import org.apache.juneau.collections.*; 030import org.apache.juneau.commons.collections.*; 031import org.apache.juneau.json.*; 032 033/** 034 * A limited subset of JSON-Schema's items object. 035 * 036 * <p> 037 * The Items Object is a limited subset of JSON-Schema's items object. It is used by parameter definitions that are 038 * not located in "body" to describe the type of items in an array. This is particularly useful for query parameters, 039 * path parameters, and header parameters that accept arrays. 040 * 041 * <h5 class='section'>OpenAPI Specification:</h5> 042 * <p> 043 * The Items Object supports the following fields from JSON Schema: 044 * <ul class='spaced-list'> 045 * <li><c>type</c> (string, REQUIRED) - The data type. Values: <js>"string"</js>, <js>"number"</js>, <js>"integer"</js>, <js>"boolean"</js>, <js>"array"</js> 046 * <li><c>format</c> (string) - The format modifier (e.g., <js>"int32"</js>, <js>"int64"</js>, <js>"float"</js>, <js>"double"</js>, <js>"date"</js>, <js>"date-time"</js>) 047 * <li><c>items</c> ({@link Items}) - Required if type is <js>"array"</js>. Describes the type of items in the array 048 * <li><c>collectionFormat</c> (string) - How multiple values are formatted. Values: <js>"csv"</js>, <js>"ssv"</js>, <js>"tsv"</js>, <js>"pipes"</js>, <js>"multi"</js> 049 * <li><c>default</c> (any) - The default value 050 * <li><c>maximum</c> (number), <c>exclusiveMaximum</c> (boolean), <c>minimum</c> (number), <c>exclusiveMinimum</c> (boolean) - Numeric constraints 051 * <li><c>maxLength</c> (integer), <c>minLength</c> (integer), <c>pattern</c> (string) - String constraints 052 * <li><c>maxItems</c> (integer), <c>minItems</c> (integer), <c>uniqueItems</c> (boolean) - Array constraints 053 * <li><c>enum</c> (array) - Possible values for this item 054 * <li><c>multipleOf</c> (number) - Must be a multiple of this value 055 * </ul> 056 * 057 * <h5 class='section'>Example:</h5> 058 * <p class='bcode'> 059 * <jc>// Construct using SwaggerBuilder.</jc> 060 * Items <jv>x</jv> = <jsm>items</jsm>(<js>"string"</js>).minLength(2); 061 * 062 * <jc>// Serialize using JsonSerializer.</jc> 063 * String <jv>json</jv> = Json.<jsm>from</jsm>(<jv>x</jv>); 064 * 065 * <jc>// Or just use toString() which does the same as above.</jc> 066 * String <jv>json</jv> = <jv>x</jv>.toString(); 067 * </p> 068 * <p class='bcode'> 069 * <jc>// Output</jc> 070 * { 071 * <js>"type"</js>: <js>"string"</js>, 072 * <js>"minLength"</js>: 2 073 * } 074 * </p> 075 * 076 * <h5 class='section'>See Also:</h5><ul> 077 * <li class='link'><a class="doclink" href="https://spec.openapis.org/oas/v3.0.0#items-object">OpenAPI Specification > Items Object</a> 078 * <li class='link'><a class="doclink" href="https://swagger.io/docs/specification/describing-parameters/">OpenAPI Describing Parameters</a> 079 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanOpenApi3">juneau-bean-openapi-v3</a> 080 * </ul> 081 */ 082public class Items extends OpenApiElement { 083 084 private static final String[] VALID_TYPES = { "string", "number", "integer", "boolean", "array" }; 085 private static final String[] VALID_COLLECTION_FORMATS = { "csv", "ssv", "tsv", "pipes", "multi" }; 086 087 private String type, format, collectionFormat, pattern, ref; 088 private Number maximum, minimum, multipleOf; 089 private Integer maxLength, minLength, maxItems, minItems; 090 private Boolean exclusiveMaximum, exclusiveMinimum, uniqueItems; 091 private Items items; // NOSONAR - Intentional naming. 092 private Object default_; 093 private List<Object> enum_ = list(); 094 095 /** 096 * Default constructor. 097 */ 098 public Items() {} 099 100 /** 101 * Copy constructor. 102 * 103 * @param copyFrom The object to copy. 104 */ 105 public Items(Items copyFrom) { 106 super(copyFrom); 107 108 this.type = copyFrom.type; 109 this.format = copyFrom.format; 110 this.collectionFormat = copyFrom.collectionFormat; 111 this.pattern = copyFrom.pattern; 112 this.maximum = copyFrom.maximum; 113 this.minimum = copyFrom.minimum; 114 this.multipleOf = copyFrom.multipleOf; 115 this.maxLength = copyFrom.maxLength; 116 this.minLength = copyFrom.minLength; 117 this.maxItems = copyFrom.maxItems; 118 this.minItems = copyFrom.minItems; 119 this.exclusiveMaximum = copyFrom.exclusiveMaximum; 120 this.exclusiveMinimum = copyFrom.exclusiveMinimum; 121 this.uniqueItems = copyFrom.uniqueItems; 122 this.items = copyFrom.items == null ? null : copyFrom.items.copy(); 123 this.default_ = copyFrom.default_; 124 if (nn(copyFrom.enum_)) 125 this.enum_.addAll(copyOf(copyFrom.enum_)); 126 this.ref = copyFrom.ref; 127 } 128 129 /** 130 * Adds one or more values to the <property>enum</property> property. 131 * 132 * @param values 133 * The values to add to this property. 134 * <br>Ignored if <jk>null</jk>. 135 * @return This object 136 */ 137 public Items addEnum(Object...values) { 138 if (nn(values)) 139 for (var v : values) 140 if (nn(v)) 141 enum_.add(v); 142 return this; 143 } 144 145 /** 146 * Make a deep copy of this object. 147 * 148 * @return A deep copy of this object. 149 */ 150 public Items copy() { 151 return new Items(this); 152 } 153 154 @Override /* Overridden from SwaggerElement */ 155 public <T> T get(String property, Class<T> type) { 156 assertArgNotNull("property", property); 157 return switch (property) { 158 case "type" -> toType(getType(), type); 159 case "format" -> toType(getFormat(), type); 160 case "items" -> toType(getItems(), type); 161 case "collectionFormat" -> toType(getCollectionFormat(), type); 162 case "default" -> toType(getDefault(), type); 163 case "maximum" -> toType(getMaximum(), type); 164 case "exclusiveMaximum" -> toType(getExclusiveMaximum(), type); 165 case "minimum" -> toType(getMinimum(), type); 166 case "exclusiveMinimum" -> toType(getExclusiveMinimum(), type); 167 case "maxLength" -> toType(getMaxLength(), type); 168 case "minLength" -> toType(getMinLength(), type); 169 case "pattern" -> toType(getPattern(), type); 170 case "maxItems" -> toType(getMaxItems(), type); 171 case "minItems" -> toType(getMinItems(), type); 172 case "uniqueItems" -> toType(getUniqueItems(), type); 173 case "enum" -> toType(getEnum(), type); 174 case "multipleOf" -> toType(getMultipleOf(), type); 175 case "$ref" -> toType(getRef(), type); 176 default -> super.get(property, type); 177 }; 178 } 179 180 /** 181 * Bean property getter: <property>collectionFormat</property>. 182 * 183 * <p> 184 * Determines the format of the array if type array is used. 185 * 186 * @return The property value, or <jk>null</jk> if it is not set. 187 */ 188 public String getCollectionFormat() { return collectionFormat; } 189 190 /** 191 * Bean property getter: <property>default</property>. 192 * 193 * <p> 194 * Declares the value of the item that the server will use if none is provided. 195 * 196 * <h5 class='section'>Notes:</h5> 197 * <ul class='spaced-list'> 198 * <li> 199 * <js>"default"</js> has no meaning for required items. 200 * <li> 201 * Unlike JSON Schema this value MUST conform to the defined <code>type</code> for the data type. 202 * </ul> 203 * 204 * @return The property value, or <jk>null</jk> if it is not set. 205 */ 206 public Object getDefault() { return default_; } 207 208 /** 209 * Bean property getter: <property>enum</property>. 210 * 211 * @return The property value, or <jk>null</jk> if it is not set. 212 */ 213 public List<Object> getEnum() { return nullIfEmpty(enum_); } 214 215 /** 216 * Bean property getter: <property>exclusiveMaximum</property>. 217 * 218 * @return The property value, or <jk>null</jk> if it is not set. 219 */ 220 public Boolean getExclusiveMaximum() { return exclusiveMaximum; } 221 222 /** 223 * Bean property getter: <property>exclusiveMinimum</property>. 224 * 225 * @return The property value, or <jk>null</jk> if it is not set. 226 */ 227 public Boolean getExclusiveMinimum() { return exclusiveMinimum; } 228 229 /** 230 * Bean property getter: <property>format</property>. 231 * 232 * <p> 233 * The extending format for the previously mentioned <code>type</code>. 234 * 235 * @return The property value, or <jk>null</jk> if it is not set. 236 */ 237 public String getFormat() { return format; } 238 239 /** 240 * Bean property getter: <property>items</property>. 241 * 242 * <p> 243 * Describes the type of items in the array. 244 * 245 * @return The property value, or <jk>null</jk> if it is not set. 246 */ 247 public Items getItems() { return items; } 248 249 /** 250 * Bean property getter: <property>maximum</property>. 251 * 252 * @return The property value, or <jk>null</jk> if it is not set. 253 */ 254 public Number getMaximum() { return maximum; } 255 256 /** 257 * Bean property getter: <property>maxItems</property>. 258 * 259 * @return The property value, or <jk>null</jk> if it is not set. 260 */ 261 public Integer getMaxItems() { return maxItems; } 262 263 /** 264 * Bean property getter: <property>maxLength</property>. 265 * 266 * @return The property value, or <jk>null</jk> if it is not set. 267 */ 268 public Integer getMaxLength() { return maxLength; } 269 270 /** 271 * Bean property getter: <property>minimum</property>. 272 * 273 * @return The property value, or <jk>null</jk> if it is not set. 274 */ 275 public Number getMinimum() { return minimum; } 276 277 /** 278 * Bean property getter: <property>minItems</property>. 279 * 280 * @return The property value, or <jk>null</jk> if it is not set. 281 */ 282 public Integer getMinItems() { return minItems; } 283 284 /** 285 * Bean property getter: <property>minLength</property>. 286 * 287 * @return The property value, or <jk>null</jk> if it is not set. 288 */ 289 public Integer getMinLength() { return minLength; } 290 291 /** 292 * Bean property getter: <property>multipleOf</property>. 293 * 294 * @return The property value, or <jk>null</jk> if it is not set. 295 */ 296 public Number getMultipleOf() { return multipleOf; } 297 298 /** 299 * Bean property getter: <property>pattern</property>. 300 * 301 * @return The property value, or <jk>null</jk> if it is not set. 302 */ 303 public String getPattern() { return pattern; } 304 305 /** 306 * Bean property getter: <property>$ref</property>. 307 * 308 * @return The property value, or <jk>null</jk> if it is not set. 309 */ 310 @Beanp("$ref") 311 public String getRef() { return ref; } 312 313 /** 314 * Bean property getter: <property>type</property>. 315 * 316 * <p> 317 * The internal type of the array. 318 * 319 * @return The property value, or <jk>null</jk> if it is not set. 320 */ 321 public String getType() { return type; } 322 323 /** 324 * Bean property getter: <property>uniqueItems</property>. 325 * 326 * @return The property value, or <jk>null</jk> if it is not set. 327 */ 328 public Boolean getUniqueItems() { return uniqueItems; } 329 330 @Override /* Overridden from SwaggerElement */ 331 public Set<String> keySet() { 332 // @formatter:off 333 var s = setb(String.class) 334 .addIf(nn(ref), "$ref") 335 .addIf(nn(collectionFormat), "collectionFormat") 336 .addIf(nn(default_), "default") 337 .addIf(ne(enum_), "enum") 338 .addIf(nn(exclusiveMaximum), "exclusiveMaximum") 339 .addIf(nn(exclusiveMinimum), "exclusiveMinimum") 340 .addIf(nn(format), "format") 341 .addIf(nn(items), "items") 342 .addIf(nn(maxItems), "maxItems") 343 .addIf(nn(maxLength), "maxLength") 344 .addIf(nn(maximum), "maximum") 345 .addIf(nn(minItems), "minItems") 346 .addIf(nn(minLength), "minLength") 347 .addIf(nn(minimum), "minimum") 348 .addIf(nn(multipleOf), "multipleOf") 349 .addIf(nn(pattern), "pattern") 350 .addIf(nn(type), "type") 351 .addIf(nn(uniqueItems), "uniqueItems") 352 .build(); 353 // @formatter:on 354 return new MultiSet<>(s, super.keySet()); 355 } 356 357 /** 358 * Resolves any <js>"$ref"</js> attributes in this element. 359 * 360 * @param openApi The swagger document containing the definitions. 361 * @param refStack Keeps track of previously-visited references so that we don't cause recursive loops. 362 * @param maxDepth 363 * The maximum depth to resolve references. 364 * <br>After that level is reached, <code>$ref</code> references will be left alone. 365 * <br>Useful if you have very complex models and you don't want your swagger page to be overly-complex. 366 * @return 367 * This object with references resolved. 368 * <br>May or may not be the same object. 369 */ 370 public Items resolveRefs(OpenApi openApi, Deque<String> refStack, int maxDepth) { 371 372 if (nn(ref)) { 373 if (refStack.contains(ref) || refStack.size() >= maxDepth) 374 return this; 375 refStack.addLast(ref); 376 var r = openApi.findRef(ref, Items.class); 377 r = r.resolveRefs(openApi, refStack, maxDepth); 378 refStack.removeLast(); 379 return r; 380 } 381 382 set("properties", resolveRefs(get("properties"), openApi, refStack, maxDepth)); 383 384 if (nn(items)) 385 items = items.resolveRefs(openApi, refStack, maxDepth); 386 387 set("example", null); 388 389 return this; 390 } 391 392 @Override /* Overridden from SwaggerElement */ 393 public Items set(String property, Object value) { 394 assertArgNotNull("property", property); 395 return switch (property) { 396 case "$ref" -> setRef(value); 397 case "collectionFormat" -> setCollectionFormat(s(value)); 398 case "default" -> setDefault(value); 399 case "enum" -> setEnum(value); 400 case "exclusiveMaximum" -> setExclusiveMaximum(toBoolean(value)); 401 case "exclusiveMinimum" -> setExclusiveMinimum(toBoolean(value)); 402 case "format" -> setFormat(s(value)); 403 case "items" -> setItems(toType(value, Items.class)); 404 case "maxItems" -> setMaxItems(toInteger(value)); 405 case "maxLength" -> setMaxLength(toInteger(value)); 406 case "maximum" -> setMaximum(toNumber(value)); 407 case "minItems" -> setMinItems(toInteger(value)); 408 case "minLength" -> setMinLength(toInteger(value)); 409 case "minimum" -> setMinimum(toNumber(value)); 410 case "multipleOf" -> setMultipleOf(toNumber(value)); 411 case "pattern" -> setPattern(s(value)); 412 case "type" -> setType(s(value)); 413 case "uniqueItems" -> setUniqueItems(toBoolean(value)); 414 default -> { 415 super.set(property, value); 416 yield this; 417 } 418 }; 419 } 420 421 /** 422 * Bean property setter: <property>collectionFormat</property>. 423 * 424 * <p> 425 * Determines the format of the array if type array is used. 426 * 427 * @param value 428 * The new value for this property. 429 * <br>Valid values: 430 * <ul> 431 * <li><js>"csv"</js> (default) - comma separated values <code>foo,bar</code>. 432 * <li><js>"ssv"</js> - space separated values <code>foo bar</code>. 433 * <li><js>"tsv"</js> - tab separated values <code>foo\tbar</code>. 434 * <li><js>"pipes"</js> - pipe separated values <code>foo|bar</code>. 435 * </ul> 436 * <br>Can be <jk>null</jk> to unset the property. 437 * @return This object 438 */ 439 public Items setCollectionFormat(String value) { 440 if (isStrict() && ! contains(value, VALID_COLLECTION_FORMATS)) 441 throw rex("Invalid value passed in to setCollectionFormat(String). Value=''{0}'', valid values=[{1}]", value, toCdl(VALID_COLLECTION_FORMATS)); 442 collectionFormat = value; 443 return this; 444 } 445 446 /** 447 * Bean property setter: <property>default</property>. 448 * 449 * <p> 450 * Declares the value of the item that the server will use if none is provided. 451 * 452 * <h5 class='section'>Notes:</h5> 453 * <ul class='spaced-list'> 454 * <li> 455 * <js>"default"</js> has no meaning for required items. 456 * <li> 457 * Unlike JSON Schema this value MUST conform to the defined <code>type</code> for the data type. 458 * </ul> 459 * 460 * @param value 461 * The new value for this property. 462 * <br>Can be <jk>null</jk> to unset the property. 463 * @return This object 464 */ 465 public Items setDefault(Object value) { 466 default_ = value; 467 return this; 468 } 469 470 /** 471 * Bean property setter: <property>enum</property>. 472 * 473 * @param value 474 * The new value for this property. 475 * <br>Can be <jk>null</jk> to unset the property. 476 * @return This object 477 */ 478 public Items setEnum(Collection<Object> value) { 479 enum_.clear(); 480 if (nn(value)) 481 enum_.addAll(value); 482 return this; 483 } 484 485 /** 486 * Adds one or more values to the <property>enum</property> property. 487 * 488 * @param values 489 * The values to add to this property. 490 * <br>Valid types: 491 * <ul> 492 * <li><code>Object</code> 493 * <li><code>Collection<Object></code> 494 * <li><code>String</code> - JSON array representation of <code>Collection<Object></code> 495 * <h5 class='figure'>Example:</h5> 496 * <p class='bcode'> 497 * enum_(<js>"['foo','bar']"</js>); 498 * </p> 499 * <li><code>String</code> - Individual values 500 * <h5 class='figure'>Example:</h5> 501 * <p class='bcode'> 502 * enum_(<js>"foo"</js>, <js>"bar"</js>); 503 * </p> 504 * </ul> 505 * <br>Ignored if <jk>null</jk>. 506 * @return This object 507 */ 508 public Items setEnum(Object...values) { // NOSONAR - Intentional naming. 509 enum_ = listb(Object.class).sparse().addAny(enum_, values).build(); 510 return this; 511 } 512 513 /** 514 * Bean property setter: <property>exclusiveMaximum</property>. 515 * 516 * @param value 517 * The new value for this property. 518 * <br>Can be <jk>null</jk> to unset the property. 519 * @return This object 520 */ 521 public Items setExclusiveMaximum(Boolean value) { 522 exclusiveMaximum = value; 523 return this; 524 } 525 526 /** 527 * Bean property setter: <property>exclusiveMinimum</property>. 528 * 529 * @param value 530 * The new value for this property. 531 * <br>Can be <jk>null</jk> to unset the property. 532 * @return This object 533 */ 534 public Items setExclusiveMinimum(Boolean value) { 535 exclusiveMinimum = value; 536 return this; 537 } 538 539 /** 540 * Bean property setter: <property>format</property>. 541 * 542 * <p> 543 * The extending format for the previously mentioned <code>type</code>. 544 * 545 * @param value 546 * The new value for this property. 547 * <br>Can be <jk>null</jk> to unset the property. 548 * @return This object 549 */ 550 public Items setFormat(String value) { 551 format = value; 552 return this; 553 } 554 555 /** 556 * Bean property setter: <property>items</property>. 557 * 558 * <p> 559 * Describes the type of items in the array. 560 * 561 * @param value 562 * The new value for this property. 563 * <br>Property value is required if <code>type</code> is <js>"array"</js>. 564 * <br>Can be <jk>null</jk> to unset the property. 565 * @return This object 566 */ 567 public Items setItems(Items value) { 568 items = value; 569 return this; 570 } 571 572 /** 573 * Bean property setter: <property>maximum</property>. 574 * 575 * @param value 576 * The new value for this property. 577 * <br>Can be <jk>null</jk> to unset the property. 578 * @return This object 579 */ 580 public Items setMaximum(Number value) { 581 maximum = value; 582 return this; 583 } 584 585 /** 586 * Bean property setter: <property>maxItems</property>. 587 * 588 * @param value 589 * The new value for this property. 590 * <br>Can be <jk>null</jk> to unset the property. 591 * @return This object 592 */ 593 public Items setMaxItems(Integer value) { 594 maxItems = value; 595 return this; 596 } 597 598 /** 599 * Bean property setter: <property>maxLength</property>. 600 * 601 * @param value 602 * The new value for this property. 603 * <br>Can be <jk>null</jk> to unset the property. 604 * @return This object 605 */ 606 public Items setMaxLength(Integer value) { 607 maxLength = value; 608 return this; 609 } 610 611 /** 612 * Bean property setter: <property>minimum</property>. 613 * 614 * @param value 615 * The new value for this property. 616 * <br>Can be <jk>null</jk> to unset the property. 617 * @return This object 618 */ 619 public Items setMinimum(Number value) { 620 minimum = value; 621 return this; 622 } 623 624 /** 625 * Bean property setter: <property>minItems</property>. 626 * 627 * @param value 628 * The new value for this property. 629 * <br>Can be <jk>null</jk> to unset the property. 630 * @return This object 631 */ 632 public Items setMinItems(Integer value) { 633 minItems = value; 634 return this; 635 } 636 637 /** 638 * Bean property setter: <property>minLength</property>. 639 * 640 * @param value 641 * The new value for this property. 642 * <br>Can be <jk>null</jk> to unset the property. 643 * @return This object 644 */ 645 public Items setMinLength(Integer value) { 646 minLength = value; 647 return this; 648 } 649 650 /** 651 * Bean property setter: <property>multipleOf</property>. 652 * 653 * @param value 654 * The new value for this property. 655 * <br>Can be <jk>null</jk> to unset the property. 656 * @return This object 657 */ 658 public Items setMultipleOf(Number value) { 659 multipleOf = value; 660 return this; 661 } 662 663 /** 664 * Bean property setter: <property>pattern</property>. 665 * 666 * <p> 667 * This string SHOULD be a valid regular expression. 668 * 669 * @param value 670 * The new value for this property. 671 * <br>Can be <jk>null</jk> to unset the property. 672 * @return This object 673 */ 674 public Items setPattern(String value) { 675 pattern = value; 676 return this; 677 } 678 679 /** 680 * Bean property setter: <property>$ref</property>. 681 * 682 * @param value 683 * The new value for this property. 684 * <br>Can be <jk>null</jk> to unset the property. 685 * @return This object 686 */ 687 @Beanp("$ref") 688 public Items setRef(Object value) { 689 ref = s(value); 690 return this; 691 } 692 693 /** 694 * Bean property setter: <property>type</property>. 695 * 696 * <p> 697 * The internal type of the array. 698 * 699 * @param value 700 * The new value for this property. 701 * <br>Valid values: 702 * <ul> 703 * <li><js>"string"</js> 704 * <li><js>"number"</js> 705 * <li><js>"integer"</js> 706 * <li><js>"boolean"</js> 707 * <li><js>"array"</js> 708 * </ul> 709 * <br>Property value is required. 710 * <br>Can be <jk>null</jk> to unset the property. 711 * @return This object 712 */ 713 public Items setType(String value) { 714 if (isStrict() && ! contains(value, VALID_TYPES)) 715 throw illegalArg("Invalid value passed in to setType(String). Value=''{0}'', valid values={1}", value, Json5Serializer.DEFAULT.toString(VALID_TYPES)); 716 type = value; 717 return this; 718 } 719 720 /** 721 * Bean property setter: <property>uniqueItems</property>. 722 * 723 * @param value 724 * The new value for this property. 725 * <br>Can be <jk>null</jk> to unset the property. 726 * @return This object 727 */ 728 public Items setUniqueItems(Boolean value) { 729 uniqueItems = value; 730 return this; 731 } 732 733 @Override /* Overridden from OpenApiElement */ 734 public Items strict(Object value) { 735 super.strict(value); 736 return this; 737 } 738 739 /* Resolve references in extra attributes */ 740 private Object resolveRefs(Object o, OpenApi openApi, Deque<String> refStack, int maxDepth) { 741 if (o instanceof JsonMap om) { 742 var ref2 = om.get("$ref"); 743 if (ref2 instanceof CharSequence) { 744 var sref = ref2.toString(); 745 if (refStack.contains(sref) || refStack.size() >= maxDepth) 746 return o; 747 refStack.addLast(sref); 748 var o2 = openApi.findRef(sref, Object.class); 749 o2 = resolveRefs(o2, openApi, refStack, maxDepth); 750 refStack.removeLast(); 751 return o2; 752 } 753 for (var e : om.entrySet()) 754 e.setValue(resolveRefs(e.getValue(), openApi, refStack, maxDepth)); 755 } 756 if (o instanceof JsonList o2) 757 for (var li = o2.listIterator(); li.hasNext();) 758 li.set(resolveRefs(li.next(), openApi, refStack, maxDepth)); 759 return o; 760 } 761 762 @Override /* Overridden from SwaggerElement */ 763 protected Items strict() { 764 super.strict(); 765 return this; 766 } 767}