001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.dto.swagger; 014 015import static org.apache.juneau.common.internal.StringUtils.*; 016import static org.apache.juneau.internal.ClassUtils.*; 017import static org.apache.juneau.internal.CollectionUtils.*; 018import static org.apache.juneau.internal.ConverterUtils.*; 019 020import java.util.*; 021 022import org.apache.juneau.*; 023import org.apache.juneau.annotation.*; 024import org.apache.juneau.collections.*; 025import org.apache.juneau.internal.*; 026import org.apache.juneau.json.*; 027import org.apache.juneau.objecttools.*; 028 029/** 030 * This is the root document object for the API specification. 031 * 032 * <h5 class='section'>See Also:</h5><ul> 033 * <li class='link'><a class="doclink" href="../../../../../index.html#jrs.Swagger">Overview > juneau-rest-server > Swagger</a> 034 * </ul> 035 */ 036@Bean(properties="swagger,info,tags,externalDocs,basePath,schemes,consumes,produces,paths,definitions,parameters,responses,securityDefinitions,security,*") 037@FluentSetters 038public class Swagger extends SwaggerElement { 039 040 /** Represents a null swagger */ 041 public static final Swagger NULL = new Swagger(); 042 043 private static final Comparator<String> PATH_COMPARATOR = (o1, o2) -> o1.replace('{', '@').compareTo(o2.replace('{', '@')); 044 045 private String 046 swagger = "2.0", 047 host, 048 basePath; 049 private Info info; 050 private ExternalDocumentation externalDocs; 051 private Set<String> schemes; 052 private Set<MediaType> 053 consumes, 054 produces; 055 private Set<Tag> tags; 056 private List<Map<String,List<String>>> security; 057 private Map<String,JsonMap> definitions; 058 private Map<String,ParameterInfo> parameters; 059 private Map<String,ResponseInfo> responses; 060 private Map<String,SecurityScheme> securityDefinitions; 061 private Map<String,OperationMap> paths; 062 063 /** 064 * Default constructor. 065 */ 066 public Swagger() {} 067 068 /** 069 * Copy constructor. 070 * 071 * @param copyFrom The object to copy. 072 */ 073 public Swagger(Swagger copyFrom) { 074 super(copyFrom); 075 076 this.basePath = copyFrom.basePath; 077 this.consumes = copyOf(copyFrom.consumes); 078 this.externalDocs = copyFrom.externalDocs == null ? null : copyFrom.externalDocs.copy(); 079 this.host = copyFrom.host; 080 this.info = copyFrom.info == null ? null : copyFrom.info.copy(); 081 this.produces = copyOf(copyFrom.produces); 082 this.schemes = copyOf(copyFrom.schemes); 083 this.swagger = copyFrom.swagger; 084 085 // TODO - Definitions are not deep copied, so they should not contain references. 086 if (copyFrom.definitions == null) { 087 this.definitions = null; 088 } else { 089 this.definitions = map(); 090 copyFrom.definitions.forEach((k,v) -> this.definitions.put(k, new JsonMap(v))); 091 } 092 093 if (copyFrom.paths == null) { 094 this.paths = null; 095 } else { 096 this.paths = map(); 097 copyFrom.paths.forEach((k,v) -> { 098 OperationMap m = new OperationMap(); 099 v.forEach((k2,v2) -> m.put(k2, v2.copy())); 100 this.paths.put(k, m); 101 }); 102 } 103 104 if (copyFrom.parameters == null) { 105 this.parameters = null; 106 } else { 107 this.parameters = map(); 108 copyFrom.parameters.forEach((k,v) -> this.parameters.put(k, v.copy())); 109 } 110 111 if (copyFrom.responses == null) { 112 this.responses = null; 113 } else { 114 this.responses = map(); 115 copyFrom.responses.forEach((k,v) -> this.responses.put(k, v.copy())); 116 } 117 118 if (copyFrom.security == null) { 119 this.security = null; 120 } else { 121 this.security = list(); 122 copyFrom.security.forEach(x -> { 123 Map<String,List<String>> m2 = map(); 124 x.forEach((k,v) -> m2.put(k, copyOf(v))); 125 this.security.add(m2); 126 }); 127 } 128 129 if (copyFrom.securityDefinitions == null) { 130 this.securityDefinitions = null; 131 } else { 132 this.securityDefinitions = map(); 133 copyFrom.securityDefinitions.forEach((k,v) -> this.securityDefinitions.put(k, v.copy())); 134 } 135 136 if (copyFrom.tags == null) { 137 this.tags = null; 138 } else { 139 this.tags = CollectionUtils.set(); 140 copyFrom.tags.forEach(x -> this.tags.add(x.copy())); 141 } 142 } 143 144 /** 145 * Make a deep copy of this object. 146 * 147 * @return A deep copy of this object. 148 */ 149 public Swagger copy() { 150 return new Swagger(this); 151 } 152 153 //----------------------------------------------------------------------------------------------------------------- 154 // Properties 155 //----------------------------------------------------------------------------------------------------------------- 156 157 /** 158 * Bean property getter: <property>basePath</property>. 159 * 160 * <p> 161 * The base path on which the API is served, which is relative to the <c>host</c>. 162 * 163 * @return The property value, or <jk>null</jk> if it is not set. 164 */ 165 public String getBasePath() { 166 return basePath; 167 } 168 169 /** 170 * Bean property setter: <property>basePath</property>. 171 * 172 * <p> 173 * The base path on which the API is served, which is relative to the <c>host</c>. 174 * 175 * @param value 176 * The new value for this property. 177 * <br>If it is not included, the API is served directly under the <c>host</c>. 178 * <br>The value MUST start with a leading slash (/). 179 * <br>The <c>basePath</c> does not support <a class="doclink" href="https://swagger.io/specification/v2#pathTemplating">path templating</a>. 180 * <br>Can be <jk>null</jk> to unset the property. 181 * @return This object. 182 */ 183 public Swagger setBasePath(String value) { 184 basePath = value; 185 return this; 186 } 187 188 /** 189 * Bean property getter: <property>consumes</property>. 190 * 191 * <p> 192 * A list of MIME types the APIs can consume. 193 * 194 * @return The property value, or <jk>null</jk> if it is not set. 195 */ 196 public Set<MediaType> getConsumes() { 197 return consumes; 198 } 199 200 /** 201 * Bean property setter: <property>consumes</property>. 202 * 203 * <p> 204 * A list of MIME types the APIs can consume. 205 * 206 * @param value 207 * The new value for this property. 208 * <br>Value MUST be as described under <a class="doclink" href="https://swagger.io/specification#mimeTypes">Swagger Mime Types</a>. 209 * <br>Can be <jk>null</jk> to unset the property. 210 * @return This object. 211 */ 212 public Swagger setConsumes(Collection<MediaType> value) { 213 consumes = setFrom(value); 214 return this; 215 } 216 217 /** 218 * Bean property appender: <property>consumes</property>. 219 * 220 * <p> 221 * A list of MIME types the APIs can consume. 222 * 223 * @param values 224 * The values to add to this property. 225 * <br>Values MUST be as described under <a class="doclink" href="https://swagger.io/specification#mimeTypes">Swagger Mime Types</a>. 226 * <br>Ignored if <jk>null</jk>. 227 * @return This object. 228 */ 229 public Swagger addConsumes(MediaType...values) { 230 consumes = setBuilder(consumes).sparse().add(values).build(); 231 return this; 232 } 233 234 /** 235 * Bean property fluent setter: <property>consumes</property>. 236 * 237 * <p> 238 * A list of MIME types the APIs can consume. 239 * 240 * @param value 241 * The values to set on this property. 242 * @return This object. 243 */ 244 public Swagger setConsumes(MediaType...value) { 245 setConsumes(setBuilder(MediaType.class).sparse().add(value).build()); 246 return this; 247 } 248 249 /** 250 * Bean property getter: <property>definitions</property>. 251 * 252 * <p> 253 * An object to hold data types produced and consumed by operations. 254 * 255 * @return The property value, or <jk>null</jk> if it is not set. 256 */ 257 public Map<String,JsonMap> getDefinitions() { 258 return definitions; 259 } 260 261 /** 262 * Bean property setter: <property>definitions</property>. 263 * 264 * <p> 265 * An object to hold data types produced and consumed by operations. 266 * 267 * @param value 268 * The new value for this property. 269 * <br>Can be <jk>null</jk> to unset the property. 270 * @return This object. 271 */ 272 public Swagger setDefinitions(Map<String,JsonMap> value) { 273 definitions = copyOf(value); 274 return this; 275 } 276 277 /** 278 * Bean property appender: <property>definitions</property>. 279 * 280 * <p> 281 * Adds a single value to the <property>definitions</property> property. 282 * 283 * @param name A definition name. 284 * @param schema The schema that the name defines. 285 * @return This object. 286 */ 287 public Swagger addDefinition(String name, JsonMap schema) { 288 definitions = mapBuilder(definitions).sparse().add(name, schema).build(); 289 return this; 290 } 291 292 /** 293 * Bean property getter: <property>externalDocs</property>. 294 * 295 * <p> 296 * Additional external documentation. 297 * 298 * @return The property value, or <jk>null</jk> if it is not set. 299 */ 300 public ExternalDocumentation getExternalDocs() { 301 return externalDocs; 302 } 303 304 /** 305 * Bean property setter: <property>externalDocs</property>. 306 * 307 * <p> 308 * Additional external documentation. 309 * 310 * @param value 311 * The new value for this property. 312 * <br>Can be <jk>null</jk> to unset the property. 313 * @return This object. 314 */ 315 public Swagger setExternalDocs(ExternalDocumentation value) { 316 externalDocs = value; 317 return this; 318 } 319 320 /** 321 * Bean property getter: <property>host</property>. 322 * 323 * <p> 324 * The host (name or IP) serving the API. 325 * 326 * @return The property value, or <jk>null</jk> if it is not set. 327 */ 328 public String getHost() { 329 return host; 330 } 331 332 /** 333 * Bean property setter: <property>host</property>. 334 * 335 * <p> 336 * The host (name or IP) serving the API. 337 * 338 * @param value 339 * The new value for this property. 340 * <br>This MUST be the host only and does not include the scheme nor sub-paths. 341 * <br>It MAY include a port. 342 * <br>If the host is not included, the host serving the documentation is to be used (including the port). 343 * <br>The host does not support <a class="doclink" href="https://swagger.io/specification/v2#pathTemplating">path templating</a> 344 * <br>Can be <jk>null</jk> to unset the property. 345 * @return This object. 346 */ 347 public Swagger setHost(String value) { 348 host = value; 349 return this; 350 } 351 352 /** 353 * Bean property getter: <property>info</property>. 354 * 355 * <p> 356 * Provides metadata about the API. 357 * 358 * @return The property value, or <jk>null</jk> if it is not set. 359 */ 360 public Info getInfo() { 361 return info; 362 } 363 364 /** 365 * Bean property setter: <property>info</property>. 366 * 367 * <p> 368 * Provides metadata about the API. 369 * 370 * @param value 371 * The new value for this property. 372 * <br>Property value is required. 373 * @return This object. 374 */ 375 public Swagger setInfo(Info value) { 376 info = value; 377 return this; 378 } 379 380 /** 381 * Bean property getter: <property>parameters</property>. 382 * 383 * <p> 384 * An object to hold parameters that can be used across operations. 385 * 386 * @return The property value, or <jk>null</jk> if it is not set. 387 */ 388 public Map<String,ParameterInfo> getParameters() { 389 return parameters; 390 } 391 392 /** 393 * Bean property setter: <property>parameters</property>. 394 * 395 * <p> 396 * An object to hold parameters that can be used across operations. 397 * 398 * @param value 399 * The new value for this property. 400 * <br>Can be <jk>null</jk> to unset the property. 401 * @return This object. 402 */ 403 public Swagger setParameters(Map<String,ParameterInfo> value) { 404 parameters = copyOf(value); 405 return this; 406 } 407 408 /** 409 * Bean property appender: <property>parameters</property>. 410 * 411 * <p> 412 * Adds a single value to the <property>parameter</property> property. 413 * 414 * @param name The parameter name. 415 * @param parameter The parameter definition. 416 * @return This object. 417 */ 418 public Swagger addParameter(String name, ParameterInfo parameter) { 419 parameters = mapBuilder(parameters).sparse().add(name, parameter).build(); 420 return this; 421 } 422 423 /** 424 * Bean property getter: <property>paths</property>. 425 * 426 * <p> 427 * The available paths and operations for the API. 428 * 429 * @return The property value, or <jk>null</jk> if it is not set. 430 */ 431 public Map<String,OperationMap> getPaths() { 432 return paths; 433 } 434 435 /** 436 * Bean property setter: <property>paths</property>. 437 * 438 * <p> 439 * The available paths and operations for the API. 440 * 441 * @param value 442 * The new value for this property. 443 * <br>Property value is required. 444 * @return This object. 445 */ 446 public Swagger setPaths(Map<String,OperationMap> value) { 447 paths = mapBuilder(String.class,OperationMap.class).sparse().sorted(PATH_COMPARATOR).addAll(value).build(); 448 return this; 449 } 450 451 /** 452 * Bean property appender: <property>paths</property>. 453 * 454 * <p> 455 * Adds a single value to the <property>paths</property> property. 456 * 457 * @param path The path template. 458 * @param methodName The HTTP method name. 459 * @param operation The operation that describes the path. 460 * @return This object. 461 */ 462 public Swagger addPath(String path, String methodName, Operation operation) { 463 if (paths == null) 464 paths = new TreeMap<>(PATH_COMPARATOR); 465 OperationMap p = paths.get(path); 466 if (p == null) { 467 p = new OperationMap(); 468 paths.put(path, p); 469 } 470 p.put(methodName, operation); 471 return this; 472 } 473 474 /** 475 * Bean property getter: <property>produces</property>. 476 * 477 * <p> 478 * A list of MIME types the APIs can produce. 479 * 480 * @return The property value, or <jk>null</jk> if it is not set. 481 */ 482 public Set<MediaType> getProduces() { 483 return produces; 484 } 485 486 /** 487 * Bean property setter: <property>produces</property>. 488 * 489 * <p> 490 * A list of MIME types the APIs can produce. 491 * 492 * @param value 493 * The new value for this property. 494 * <br>Value MUST be as described under <a class="doclink" href="https://swagger.io/specification#mimeTypes">Swagger Mime Types</a>. 495 * <br>Can be <jk>null</jk> to unset the property. 496 * @return This object. 497 */ 498 public Swagger setProduces(Collection<MediaType> value) { 499 produces = setFrom(value); 500 return this; 501 } 502 503 /** 504 * Adds one or more values to the <property>produces</property> property. 505 * 506 * <p> 507 * A list of MIME types the APIs can produce. 508 * 509 * @param values 510 * The values to add to this property. 511 * <br>Value MUST be as described under <a class="doclink" href="https://swagger.io/specification#mimeTypes">Swagger Mime Types</a>. 512 * <br>Can be <jk>null</jk> to unset the property. 513 * @return This object. 514 */ 515 public Swagger addProduces(MediaType...values) { 516 produces = setBuilder(produces).sparse().add(values).build(); 517 return this; 518 } 519 520 /** 521 * Bean property fluent setter: <property>produces</property>. 522 * 523 * <p> 524 * A list of MIME types the APIs can produce. 525 * 526 * @param value 527 * The new value for this property. 528 * @return This object. 529 */ 530 public Swagger setProduces(MediaType...value) { 531 setProduces(setBuilder(MediaType.class).sparse().add(value).build()); 532 return this; 533 } 534 535 /** 536 * Bean property getter: <property>responses</property>. 537 * 538 * <p> 539 * An object to hold responses that can be used across operations. 540 * 541 * @return The property value, or <jk>null</jk> if it is not set. 542 */ 543 public Map<String,ResponseInfo> getResponses() { 544 return responses; 545 } 546 547 /** 548 * Bean property setter: <property>responses</property>. 549 * 550 * <p> 551 * An object to hold responses that can be used across operations. 552 * 553 * @param value 554 * The new value for this property. 555 * <br>Can be <jk>null</jk> to unset the property. 556 * @return This object. 557 */ 558 public Swagger setResponses(Map<String,ResponseInfo> value) { 559 responses = copyOf(value); 560 return this; 561 } 562 563 /** 564 * Bean property appender: <property>responses</property>. 565 * 566 * <p> 567 * Adds a single value to the <property>responses</property> property. 568 * 569 * @param name The response name. 570 * @param response The response definition. 571 * @return This object. 572 */ 573 public Swagger addResponse(String name, ResponseInfo response) { 574 responses = mapBuilder(responses).sparse().add(name, response).build(); 575 return this; 576 } 577 578 /** 579 * Bean property getter: <property>schemes</property>. 580 * 581 * <p> 582 * The transfer protocol of the API. 583 * 584 * @return The property value, or <jk>null</jk> if it is not set. 585 */ 586 public Set<String> getSchemes() { 587 return schemes; 588 } 589 590 /** 591 * Bean property setter: <property>schemes</property>. 592 * 593 * <p> 594 * The transfer protocol of the API. 595 * 596 * @param value 597 * The new value for this property. 598 * <br>Valid values: 599 * <ul> 600 * <li><js>"http"</js> 601 * <li><js>"https"</js> 602 * <li><js>"ws"</js> 603 * <li><js>"wss"</js> 604 * </ul> 605 * <br>Can be <jk>null</jk> to unset the property. 606 * @return This object. 607 */ 608 public Swagger setSchemes(Collection<String> value) { 609 schemes = setFrom(value); 610 return this; 611 } 612 613 /** 614 * Bean property appender: <property>schemes</property>. 615 * 616 * <p> 617 * The transfer protocol of the API. 618 * 619 * @param values 620 * The values to add to this property. 621 * <br>Valid values: 622 * <ul> 623 * <li><js>"http"</js> 624 * <li><js>"https"</js> 625 * <li><js>"ws"</js> 626 * <li><js>"wss"</js> 627 * </ul> 628 * <br>Ignored if <jk>null</jk>. 629 * @return This object. 630 */ 631 public Swagger addSchemes(String...values) { 632 schemes = setBuilder(schemes).sparse().add(values).build(); 633 return this; 634 } 635 636 /** 637 * Bean property fluent setter: <property>schemes</property>. 638 * 639 * <p> 640 * The transfer protocol of the API. 641 * 642 * @param value 643 * The new value for this property. 644 * <br>Strings can be JSON arrays. 645 * @return This object. 646 */ 647 public Swagger setSchemes(String...value) { 648 setSchemes(setBuilder(String.class).sparse().addJson(value).build()); 649 return this; 650 } 651 652 /** 653 * Bean property getter: <property>security</property>. 654 * 655 * <p> 656 * A declaration of which security schemes are applied for the API as a whole. 657 * 658 * @return The property value, or <jk>null</jk> if it is not set. 659 */ 660 public List<Map<String,List<String>>> getSecurity() { 661 return security; 662 } 663 664 /** 665 * Bean property setter: <property>security</property>. 666 * 667 * <p> 668 * A declaration of which security schemes are applied for the API as a whole. 669 * 670 * @param value 671 * The new value for this property. 672 * <br>Can be <jk>null</jk> to unset the property. 673 * @return This object. 674 */ 675 public Swagger setSecurity(Collection<Map<String,List<String>>> value) { 676 security = listFrom(value); 677 return this; 678 } 679 680 /** 681 * Bean property appender: <property>security</property>. 682 * 683 * <p> 684 * Adds a single value to the <property>securityDefinitions</property> property. 685 * 686 * @param scheme The security scheme that applies to this operation 687 * @param alternatives 688 * The list of values describes alternative security schemes that can be used (that is, there is a logical OR between the security requirements). 689 * @return This object. 690 */ 691 public Swagger addSecurity(String scheme, String...alternatives) { 692 Map<String,List<String>> m = map(); 693 m.put(scheme, alist(alternatives)); 694 security = listBuilder(security).sparse().addAll(Collections.singleton(m)).build(); 695 return this; 696 } 697 698 /** 699 * Bean property getter: <property>securityDefinitions</property>. 700 * 701 * <p> 702 * Security scheme definitions that can be used across the specification. 703 * 704 * @return The property value, or <jk>null</jk> if it is not set. 705 */ 706 public Map<String,SecurityScheme> getSecurityDefinitions() { 707 return securityDefinitions; 708 } 709 710 /** 711 * Bean property setter: <property>securityDefinitions</property>. 712 * 713 * <p> 714 * Security scheme definitions that can be used across the specification. 715 * 716 * @param value 717 * The new value for this property. 718 * <br>Can be <jk>null</jk> to unset the property. 719 * @return This object. 720 */ 721 public Swagger setSecurityDefinitions(Map<String,SecurityScheme> value) { 722 securityDefinitions = copyOf(value); 723 return this; 724 } 725 726 /** 727 * Bean property appender: <property>securityDefinitions</property>. 728 * 729 * <p> 730 * Adds a single value to the <property>securityDefinitions</property> property. 731 * 732 * @param name A security name. 733 * @param securityScheme A security schema. 734 * @return This object. 735 */ 736 public Swagger addSecurityDefinition(String name, SecurityScheme securityScheme) { 737 securityDefinitions = mapBuilder(securityDefinitions).sparse().add(name, securityScheme).build(); 738 return this; 739 } 740 741 /** 742 * Bean property getter: <property>swagger</property>. 743 * 744 * <p> 745 * Specifies the Swagger Specification version being used. 746 * 747 * @return The property value, or <jk>null</jk> if it is not set. 748 */ 749 public String getSwagger() { 750 return swagger; 751 } 752 753 /** 754 * Bean property setter: <property>swagger</property>. 755 * 756 * <p> 757 * Specifies the Swagger Specification version being used. 758 * 759 * @param value 760 * The new value for this property. 761 * <br>Property value is required. 762 * @return This object. 763 */ 764 public Swagger setSwagger(String value) { 765 swagger = value; 766 return this; 767 } 768 769 /** 770 * Bean property getter: <property>tags</property>. 771 * 772 * <p> 773 * A list of tags used by the specification with additional metadata. 774 * 775 * @return The property value, or <jk>null</jk> if it is not set. 776 */ 777 public Set<Tag> getTags() { 778 return tags; 779 } 780 781 /** 782 * Bean property setter: <property>tags</property>. 783 * 784 * <p> 785 * A list of tags used by the specification with additional metadata. 786 * 787 * @param value 788 * The new value for this property. 789 * <br>The order of the tags can be used to reflect on their order by the parsing tools. 790 * <br>Not all tags that are used by the <a class="doclink" href="https://swagger.io/specification/v2#operationObject">Operation Object</a> must be declared. 791 * <br>The tags that are not declared may be organized randomly or based on the tools' logic. 792 * <br>Each tag name in the list MUST be unique. 793 * <br>Can be <jk>null</jk> to unset the property. 794 * @return This object. 795 */ 796 public Swagger setTags(Collection<Tag> value) { 797 tags = setFrom(value); 798 return this; 799 } 800 801 /** 802 * Bean property appender: <property>tags</property>. 803 * 804 * <p> 805 * A list of tags used by the specification with additional metadata. 806 * 807 * @param values 808 * The values to add to this property. 809 * <br>The order of the tags can be used to reflect on their order by the parsing tools. 810 * <br>Not all tags that are used by the <a class="doclink" href="https://swagger.io/specification/v2#operationObject">Operation Object</a> must be declared. 811 * <br>The tags that are not declared may be organized randomly or based on the tools' logic. 812 * <br>Each tag name in the list MUST be unique. 813 * <br>Ignored if <jk>null</jk>. 814 * @return This object. 815 */ 816 public Swagger addTags(Tag...values) { 817 tags = setBuilder(tags).sparse().add(values).build(); 818 return this; 819 } 820 821 //----------------------------------------------------------------------------------------------------------------- 822 // Convenience methods 823 //----------------------------------------------------------------------------------------------------------------- 824 825 /** 826 * Shortcut for calling <c>getPaths().get(path);</c> 827 * 828 * @param path The path (e.g. <js>"/foo"</js>). 829 * @return The operation map for the specified path, or <jk>null</jk> if it doesn't exist. 830 */ 831 public OperationMap getPath(String path) { 832 return getPaths().get(path); 833 } 834 835 /** 836 * Shortcut for calling <c>getPaths().get(path).get(operation);</c> 837 * 838 * @param path The path (e.g. <js>"/foo"</js>). 839 * @param operation The HTTP operation (e.g. <js>"get"</js>). 840 * @return The operation for the specified path and operation id, or <jk>null</jk> if it doesn't exist. 841 */ 842 public Operation getOperation(String path, String operation) { 843 OperationMap om = getPath(path); 844 if (om == null) 845 return null; 846 return om.get(operation); 847 } 848 849 /** 850 * Shortcut for calling <c>getPaths().get(path).get(operation).getResponse(status);</c> 851 * 852 * @param path The path (e.g. <js>"/foo"</js>). 853 * @param operation The HTTP operation (e.g. <js>"get"</js>). 854 * @param status The HTTP response status (e.g. <js>"200"</js>). 855 * @return The operation for the specified path and operation id, or <jk>null</jk> if it doesn't exist. 856 */ 857 public ResponseInfo getResponseInfo(String path, String operation, String status) { 858 OperationMap om = getPath(path); 859 if (om == null) 860 return null; 861 Operation op = om.get(operation); 862 if (op == null) 863 return null; 864 return op.getResponse(status); 865 } 866 867 /** 868 * Shortcut for calling <c>getPaths().get(path).get(operation).getResponse(status);</c> 869 * 870 * @param path The path (e.g. <js>"/foo"</js>). 871 * @param operation The HTTP operation (e.g. <js>"get"</js>). 872 * @param status The HTTP response status (e.g. <js>"200"</js>). 873 * @return The operation for the specified path and operation id, or <jk>null</jk> if it doesn't exist. 874 */ 875 public ResponseInfo getResponseInfo(String path, String operation, int status) { 876 return getResponseInfo(path, operation, String.valueOf(status)); 877 } 878 879 /** 880 * Convenience method for calling <c>getPath(path).get(method).getParameter(in,name);</c> 881 * 882 * @param path The HTTP path. 883 * @param method The HTTP method. 884 * @param in The parameter type. 885 * @param name The parameter name. 886 * @return The parameter information or <jk>null</jk> if not found. 887 */ 888 public ParameterInfo getParameterInfo(String path, String method, String in, String name) { 889 OperationMap om = getPath(path); 890 if (om != null) { 891 Operation o = om.get(method); 892 if (o != null) { 893 return o.getParameter(in, name); 894 } 895 } 896 return null; 897 } 898 899 // <FluentSetters> 900 901 // </FluentSetters> 902 903 @Override /* SwaggerElement */ 904 public <T> T get(String property, Class<T> type) { 905 if (property == null) 906 return null; 907 switch (property) { 908 case "basePath": return toType(getBasePath(), type); 909 case "consumes": return toType(getConsumes(), type); 910 case "definitions": return toType(getDefinitions(), type); 911 case "externalDocs": return toType(getExternalDocs(), type); 912 case "host": return toType(getHost(), type); 913 case "info": return toType(getInfo(), type); 914 case "parameters": return toType(getParameters(), type); 915 case "paths": return toType(getPaths(), type); 916 case "produces": return toType(getProduces(), type); 917 case "responses": return toType(getResponses(), type); 918 case "schemes": return toType(getSchemes(), type); 919 case "security": return toType(getSecurity(), type); 920 case "securityDefinitions": return toType(getSecurityDefinitions(), type); 921 case "swagger": return toType(getSwagger(), type); 922 case "tags": return toType(getTags(), type); 923 default: return super.get(property, type); 924 } 925 } 926 927 @SuppressWarnings({ "unchecked", "rawtypes" }) 928 @Override /* SwaggerElement */ 929 public Swagger set(String property, Object value) { 930 if (property == null) 931 return this; 932 switch (property) { 933 case "basePath": return setBasePath(stringify(value)); 934 case "consumes": return setConsumes(listBuilder(MediaType.class).sparse().addAny(value).build()); 935 case "definitions": return setDefinitions(mapBuilder(String.class,JsonMap.class).sparse().addAny(value).build()); 936 case "externalDocs": return setExternalDocs(toType(value, ExternalDocumentation.class)); 937 case "host": return setHost(stringify(value)); 938 case "info": return setInfo(toType(value, Info.class)); 939 case "parameters": return setParameters(mapBuilder(String.class,ParameterInfo.class).sparse().addAny(value).build()); 940 case "paths": return setPaths(mapBuilder(String.class,OperationMap.class).sparse().addAny(value).build()); 941 case "produces": return setProduces(listBuilder(MediaType.class).sparse().addAny(value).build()); 942 case "responses": return setResponses(mapBuilder(String.class,ResponseInfo.class).sparse().addAny(value).build()); 943 case "schemes": return setSchemes(listBuilder(String.class).sparse().addAny(value).build()); 944 case "security": return setSecurity((List)listBuilder(Map.class,String.class,List.class,String.class).sparse().addAny(value).build()); 945 case "securityDefinitions": return setSecurityDefinitions(mapBuilder(String.class,SecurityScheme.class).sparse().addAny(value).build()); 946 case "swagger": return setSwagger(stringify(value)); 947 case "tags": return setTags(listBuilder(Tag.class).sparse().addAny(value).build()); 948 default: 949 super.set(property, value); 950 return this; 951 } 952 } 953 954 @Override /* SwaggerElement */ 955 public Set<String> keySet() { 956 Set<String> s = setBuilder(String.class) 957 .addIf(basePath != null, "basePath") 958 .addIf(consumes != null, "consumes") 959 .addIf(definitions != null, "definitions") 960 .addIf(externalDocs != null, "externalDocs") 961 .addIf(host != null, "host") 962 .addIf(info != null, "info") 963 .addIf(parameters != null, "parameters") 964 .addIf(paths != null, "paths") 965 .addIf(produces != null, "produces") 966 .addIf(responses != null, "responses") 967 .addIf(schemes != null, "schemes") 968 .addIf(security != null, "security") 969 .addIf(securityDefinitions != null, "securityDefinitions") 970 .addIf(swagger != null, "swagger") 971 .addIf(tags != null, "tags") 972 .build(); 973 return new MultiSet<>(s, super.keySet()); 974 } 975 976 /** 977 * A synonym of {@link #toString()}. 978 * @return This object serialized as JSON. 979 */ 980 public String asJson() { 981 return toString(); 982 } 983 984 @Override /* Object */ 985 public String toString() { 986 return JsonSerializer.DEFAULT.toString(this); 987 } 988 989 /** 990 * Resolves a <js>"$ref"</js> tags to nodes in this swagger document. 991 * 992 * @param <T> The class to convert the reference to. 993 * @param ref The ref tag value. 994 * @param c The class to convert the reference to. 995 * @return The referenced node, or <jk>null</jk> if the ref was <jk>null</jk> or empty or not found. 996 */ 997 public <T> T findRef(String ref, Class<T> c) { 998 if (isEmpty(ref)) 999 return null; 1000 if (! ref.startsWith("#/")) 1001 throw new BasicRuntimeException("Unsupported reference: ''{0}''", ref); 1002 try { 1003 return new ObjectRest(this).get(ref.substring(1), c); 1004 } catch (Exception e) { 1005 throw new BeanRuntimeException(e, c, "Reference ''{0}'' could not be converted to type ''{1}''.", ref, className(c)); 1006 } 1007 } 1008}