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