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.swagger; 018 019import static org.apache.juneau.commons.utils.CollectionUtils.*; 020import static org.apache.juneau.bean.swagger.SwaggerCopyUtils.*; 021import static org.apache.juneau.commons.utils.Shorts.*; 022import static org.apache.juneau.marshall.internal.ConverterUtils.*; 023 024import java.util.*; 025 026import org.apache.juneau.commons.collections.*; 027import org.apache.juneau.commons.http.*; 028import org.apache.juneau.marshall.collections.*; 029import org.apache.juneau.marshall.marshaller.*; 030import org.apache.juneau.marshall.objecttools.*; 031 032/** 033 * This is the root document object for the Swagger 2.0 API specification. 034 * 035 * <p> 036 * The Swagger Object is the root document that describes an entire API. It contains metadata about the API, 037 * available paths and operations, parameters, responses, security definitions, and other information. This is 038 * the Swagger 2.0 specification (predecessor to OpenAPI 3.0). 039 * 040 * <h5 class='section'>Swagger Specification:</h5> 041 * <p> 042 * The Swagger Object is composed of the following fields: 043 * <ul class='spaced-list'> 044 * <li><c>swagger</c> (string, REQUIRED) - The Swagger Specification version (must be <js>"2.0"</js>) 045 * <li><c>info</c> ({@link Info}, REQUIRED) - Provides metadata about the API 046 * <li><c>host</c> (string) - The host (name or IP) serving the API 047 * <li><c>basePath</c> (string) - The base path on which the API is served (relative to host) 048 * <li><c>schemes</c> (array of string) - The transfer protocols of the API (e.g., <js>"http"</js>, <js>"https"</js>) 049 * <li><c>consumes</c> (array of string) - A list of MIME types the APIs can consume 050 * <li><c>produces</c> (array of string) - A list of MIME types the APIs can produce 051 * <li><c>paths</c> (map of {@link OperationMap}, REQUIRED) - The available paths and operations for the API 052 * <li><c>definitions</c> (map of {@link SchemaInfo}) - Schema definitions that can be referenced 053 * <li><c>parameters</c> (map of {@link ParameterInfo}) - Parameters definitions that can be referenced 054 * <li><c>responses</c> (map of {@link ResponseInfo}) - Response definitions that can be referenced 055 * <li><c>securityDefinitions</c> (map of {@link SecurityScheme}) - Security scheme definitions 056 * <li><c>security</c> (array of map) - Security requirements applied to all operations 057 * <li><c>tags</c> (array of {@link Tag}) - A list of tags used by the specification with additional metadata 058 * <li><c>externalDocs</c> ({@link ExternalDocumentation}) - Additional external documentation 059 * </ul> 060 * 061 * <h5 class='section'>Example:</h5> 062 * <p class='bjava'> 063 * <jc>// Create a Swagger document</jc> 064 * Swagger <jv>doc</jv> = <jk>new</jk> Swagger() 065 * .setSwagger(<js>"2.0"</js>) 066 * .setInfo( 067 * <jk>new</jk> Info() 068 * .setTitle(<js>"Pet Store API"</js>) 069 * .setVersion(<js>"1.0.0"</js>) 070 * ) 071 * .setHost(<js>"petstore.swagger.io"</js>) 072 * .setBasePath(<js>"/v2"</js>) 073 * .setSchemes(<js>"https"</js>) 074 * .addPath(<js>"/pets"</js>, <js>"get"</js>, 075 * <jk>new</jk> Operation() 076 * .setSummary(<js>"List all pets"</js>) 077 * .addResponse(<js>"200"</js>, <jk>new</jk> ResponseInfo(<js>"Success"</js>)) 078 * ); 079 * </p> 080 * 081 * <h5 class='section'>See Also:</h5><ul> 082 * <li class='link'><a class="doclink" href="https://swagger.io/specification/v2/">Swagger 2.0 Specification</a> 083 * <li class='link'><a class="doclink" href="https://swagger.io/docs/specification/2-0/basic-structure/">Swagger Basic Structure</a> 084 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanSwagger2">juneau-bean-swagger-v2</a> 085 * </ul> 086 */ 087@SuppressWarnings({ 088 "java:S1192" // Duplicated literals (argument/property names) read more clearly inline than as constants 089}) 090public class Swagger extends SwaggerElement { 091 092 private static interface MapOfStringLists extends Map<String,List<String>> {} 093 094 /** Represents a null swagger */ 095 public static final Swagger NULL = new Swagger(); 096 097 private static final Comparator<String> PATH_COMPARATOR = (o1, o2) -> o1.replace('{', '@').compareTo(o2.replace('{', '@')); 098 099 private String swagger = "2.0"; 100 private String host; 101 private String basePath; 102 private Info info; 103 private ExternalDocumentation externalDocs; 104 private final Set<String> schemes = st(); 105 private final Set<MediaType> consumes = st(); 106 private final Set<MediaType> produces = st(); 107 private final Set<Tag> tags = st(); 108 private final List<Map<String,List<String>>> security = list(); 109 private final Map<String,JsonMap> definitions = map(); 110 private final Map<String,ParameterInfo> parameters = map(); 111 private final Map<String,ResponseInfo> responses = map(); 112 private final Map<String,SecurityScheme> securityDefinitions = map(); 113 114 private final Map<String,OperationMap> paths = new TreeMap<>(PATH_COMPARATOR); 115 116 /** 117 * Default constructor. 118 */ 119 public Swagger() {} 120 121 /** 122 * Copy constructor. 123 * 124 * @param copyFrom The object to copy. 125 */ 126 public Swagger(Swagger copyFrom) { 127 super(copyFrom); 128 129 this.basePath = copyFrom.basePath; 130 this.consumes.addAll(copyOf(copyFrom.consumes)); 131 this.externalDocs = copyOf(copyFrom.externalDocs); 132 this.host = copyFrom.host; 133 this.info = copyOf(copyFrom.info); 134 this.produces.addAll(copyOf(copyFrom.produces)); 135 this.schemes.addAll(copyOf(copyFrom.schemes)); 136 this.swagger = copyFrom.swagger; 137 138 definitions.putAll(copyOf(copyFrom.definitions, JsonMap::new)); 139 140 copyFrom.paths.forEach((k, v) -> { 141 var m = new OperationMap(); 142 v.forEach((k2, v2) -> m.put(k2, v2.copy())); 143 paths.put(k, m); 144 }); 145 146 parameters.putAll(copyOf(copyFrom.parameters, ParameterInfo::copy)); 147 responses.putAll(copyOf(copyFrom.responses, ResponseInfo::copy)); 148 securityDefinitions.putAll(copyOf(copyFrom.securityDefinitions, SecurityScheme::copy)); 149 150 copyFrom.security.forEach(x -> { 151 Map<String,List<String>> m2 = map(); 152 x.forEach((k, v) -> m2.put(k, copyOf(v))); 153 security.add(m2); 154 }); 155 156 this.tags.addAll(copyOf(copyFrom.tags, Tag::copy)); 157 } 158 159 /** 160 * Bean property appender: <property>consumes</property>. 161 * 162 * <p> 163 * A list of MIME types the APIs can consume. 164 * 165 * @param values 166 * The values to add to this property. 167 * <br>Ignored if <jk>null</jk>. 168 * @return This object. 169 */ 170 public Swagger addConsumes(Collection<MediaType> values) { 171 if (nn(values)) 172 consumes.addAll(values); 173 return this; 174 } 175 176 /** 177 * Bean property appender: <property>consumes</property>. 178 * 179 * <p> 180 * A list of MIME types the APIs can consume. 181 * 182 * @param values 183 * The values to add to this property. 184 * <br>Values MUST be as described under <a class="doclink" href="https://swagger.io/specification#mimeTypes">Swagger Mime Types</a>. 185 * <br>Ignored if <jk>null</jk>. 186 * @return This object. 187 */ 188 public Swagger addConsumes(MediaType...values) { 189 addAllNn(consumes, values); 190 return this; 191 } 192 193 /** 194 * Bean property appender: <property>definitions</property>. 195 * 196 * <p> 197 * Adds a single value to the <property>definitions</property> property. 198 * 199 * @param name A definition name. Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 200 * @param schema The schema that the name defines. Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 201 * @return This object. 202 */ 203 public Swagger addDefinition(String name, JsonMap schema) { 204 reqnn("name", name); 205 reqnn("schema", schema); 206 definitions.put(name, schema); 207 return this; 208 } 209 210 /** 211 * Bean property appender: <property>parameters</property>. 212 * 213 * <p> 214 * Adds a single value to the <property>parameter</property> property. 215 * 216 * @param name The parameter name. Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 217 * @param parameter The parameter definition. Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 218 * @return This object. 219 */ 220 public Swagger addParameter(String name, ParameterInfo parameter) { 221 reqnn("name", name); 222 reqnn("parameter", parameter); 223 parameters.put(name, parameter); 224 return this; 225 } 226 227 /** 228 * Bean property appender: <property>paths</property>. 229 * 230 * <p> 231 * Adds a single value to the <property>paths</property> property. 232 * 233 * @param path The path template. Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 234 * @param methodName The HTTP method name. Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 235 * @param operation The operation that describes the path. Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 236 * @return This object. 237 */ 238 public Swagger addPath(String path, String methodName, Operation operation) { 239 reqnn("path", path); 240 reqnn("methodName", methodName); 241 reqnn("operation", operation); 242 paths.computeIfAbsent(path, k -> new OperationMap()).put(methodName, operation); 243 return this; 244 } 245 246 /** 247 * Bean property appender: <property>paths</property>. 248 * 249 * <p> 250 * Adds a single operation for the specified path and HTTP method. 251 * 252 * <p> 253 * Functionally identical to {@link #addPath(String,String,Operation)}, but distinctly named so that this 254 * "add a single operation" call isn't confused with the OpenAPI 3 <c>OpenApi.addPath(String,PathItem)</c> 255 * method, which adds an entire <c>PathItem</c> (all methods for a path) at once. 256 * 257 * @param path The path template. Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 258 * @param method The HTTP method name. Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 259 * @param operation The operation that describes the path. Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 260 * @return This object. 261 */ 262 public Swagger addOperation(String path, String method, Operation operation) { 263 return addPath(path, method, operation); 264 } 265 266 /** 267 * Bean property appender: <property>produces</property>. 268 * 269 * <p> 270 * A list of MIME types the APIs can produce. 271 * 272 * @param values 273 * The values to add to this property. 274 * <br>Value MUST be as described under <a class="doclink" href="https://swagger.io/specification#mimeTypes">Swagger Mime Types</a>. 275 * <br>Ignored if <jk>null</jk>. 276 * @return This object. 277 */ 278 public Swagger addProduces(Collection<MediaType> values) { 279 if (nn(values)) 280 produces.addAll(values); 281 return this; 282 } 283 284 /** 285 * Adds one or more values to the <property>produces</property> property. 286 * 287 * <p> 288 * A list of MIME types the APIs can produce. 289 * 290 * @param values 291 * The values to add to this property. 292 * <br>Value MUST be as described under <a class="doclink" href="https://swagger.io/specification#mimeTypes">Swagger Mime Types</a>. 293 * <br>Can be <jk>null</jk> to unset the property. 294 * @return This object. 295 */ 296 public Swagger addProduces(MediaType...values) { 297 addAllNn(produces, values); 298 return this; 299 } 300 301 /** 302 * Bean property appender: <property>responses</property>. 303 * 304 * <p> 305 * Adds a single value to the <property>responses</property> property. 306 * 307 * @param name The response name. Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 308 * @param response The response definition. Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 309 * @return This object. 310 */ 311 public Swagger addResponse(String name, ResponseInfo response) { 312 reqnn("name", name); 313 reqnn("response", response); 314 responses.put(name, response); 315 return this; 316 } 317 318 /** 319 * Bean property appender: <property>schemes</property>. 320 * 321 * <p> 322 * The transfer protocol of the API. 323 * 324 * @param values 325 * The values to add to this property. 326 * <br>Valid values: 327 * <ul> 328 * <li><js>"http"</js> 329 * <li><js>"https"</js> 330 * <li><js>"ws"</js> 331 * <li><js>"wss"</js> 332 * </ul> 333 * <br>Ignored if <jk>null</jk>. 334 * @return This object. 335 */ 336 public Swagger addSchemes(Collection<String> values) { 337 if (nn(values)) 338 schemes.addAll(values); 339 return this; 340 } 341 342 /** 343 * Bean property appender: <property>schemes</property>. 344 * 345 * <p> 346 * The transfer protocol of the API. 347 * 348 * @param values 349 * The values to add to this property. 350 * <br>Valid values: 351 * <ul> 352 * <li><js>"http"</js> 353 * <li><js>"https"</js> 354 * <li><js>"ws"</js> 355 * <li><js>"wss"</js> 356 * </ul> 357 * <br>Ignored if <jk>null</jk>. 358 * @return This object. 359 */ 360 public Swagger addSchemes(String...values) { 361 addAllNn(schemes, values); 362 return this; 363 } 364 365 /** 366 * Bean property fluent setter: <property>security</property>. 367 * 368 * <p> 369 * A declaration of which security schemes are applied for the API as a whole. 370 * 371 * @param values 372 * The values to add to this property. 373 * <br>Ignored if <jk>null</jk>. 374 * @return This object. 375 */ 376 public Swagger addSecurity(Collection<Map<String,List<String>>> values) { 377 if (nn(values)) 378 security.addAll(values); 379 return this; 380 } 381 382 /** 383 * Bean property appender: <property>security</property>. 384 * 385 * <p> 386 * Adds a single value to the <property>securityDefinitions</property> property. 387 * 388 * @param scheme The security scheme that applies to this operation Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 389 * @param alternatives 390 * The list of values describes alternative security schemes that can be used (that is, there is a logical OR between the security requirements). 391 * @return This object. 392 */ 393 public Swagger addSecurity(String scheme, String...alternatives) { 394 reqnn("scheme", scheme); 395 Map<String,List<String>> m = map(); 396 m.put(scheme, l(alternatives)); 397 security.add(m); 398 return this; 399 } 400 401 /** 402 * Bean property appender: <property>securityDefinitions</property>. 403 * 404 * <p> 405 * Adds a single value to the <property>securityDefinitions</property> property. 406 * 407 * @param name A security name. Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 408 * @param securityScheme A security schema. Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 409 * @return This object. 410 */ 411 public Swagger addSecurityDefinition(String name, SecurityScheme securityScheme) { 412 reqnn("name", name); 413 reqnn("securityScheme", securityScheme); 414 securityDefinitions.put(name, securityScheme); 415 return this; 416 } 417 418 /** 419 * Bean property appender: <property>tags</property>. 420 * 421 * <p> 422 * A list of tags used by the specification with additional metadata. 423 * 424 * @param values 425 * The values to add to this property. 426 * <br>The order of the tags can be used to reflect on their order by the parsing tools. 427 * <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. 428 * <br>The tags that are not declared may be organized randomly or based on the tools' logic. 429 * <br>Each tag name in the list MUST be unique. 430 * <br>Ignored if <jk>null</jk>. 431 * @return This object. 432 */ 433 public Swagger addTags(Collection<Tag> values) { 434 if (nn(values)) 435 tags.addAll(values); 436 return this; 437 } 438 439 /** 440 * Bean property appender: <property>tags</property>. 441 * 442 * <p> 443 * A list of tags used by the specification with additional metadata. 444 * 445 * @param values 446 * The values to add to this property. 447 * <br>The order of the tags can be used to reflect on their order by the parsing tools. 448 * <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. 449 * <br>The tags that are not declared may be organized randomly or based on the tools' logic. 450 * <br>Each tag name in the list MUST be unique. 451 * <br>Ignored if <jk>null</jk>. 452 * @return This object. 453 */ 454 public Swagger addTags(Tag...values) { 455 addAllNn(tags, values); 456 return this; 457 } 458 459 /** 460 * A synonym of {@link #toString()}. 461 * @return This object serialized as JSON. 462 */ 463 public String asJson() { 464 return toString(); 465 } 466 467 /** 468 * Make a deep copy of this object. 469 * 470 * @return A deep copy of this object. 471 */ 472 public Swagger copy() { 473 return new Swagger(this); 474 } 475 476 /** 477 * Resolves a <js>"$ref"</js> tags to nodes in this swagger document. 478 * 479 * @param <T> The class to convert the reference to. 480 * @param ref The ref tag value. Must not be <jk>null</jk> or blank, or an {@link IllegalArgumentException} is thrown. 481 * @param c The class to convert the reference to. Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 482 * @return The referenced node, or <jk>null</jk> if not found. 483 */ 484 public <T> T findRef(String ref, Class<T> c) { 485 reqnb("ref", ref); 486 reqnn("c", c); 487 if (! ref.startsWith("#/")) 488 throw rex("Unsupported reference: '%s'", ref); 489 try { 490 return new PathTraversal(this).get(ref.substring(1), c); 491 } catch (Exception e) { 492 throw brex(e, c, "Reference '%s' could not be converted to type '%s'.", ref, cn(c)); 493 } 494 } 495 496 @Override /* Overridden from SwaggerElement */ 497 public <T> T get(String property, Class<T> type) { 498 reqnn("property", property); 499 return switch (property) { 500 case "basePath" -> toType(getBasePath(), type); 501 case "consumes" -> toType(getConsumes(), type); 502 case "definitions" -> toType(getDefinitions(), type); 503 case "externalDocs" -> toType(getExternalDocs(), type); 504 case "host" -> toType(getHost(), type); 505 case "info" -> toType(getInfo(), type); 506 case "parameters" -> toType(getParameters(), type); 507 case "paths" -> toType(getPaths(), type); 508 case "produces" -> toType(getProduces(), type); 509 case "responses" -> toType(getResponses(), type); 510 case "schemes" -> toType(getSchemes(), type); 511 case "security" -> toType(getSecurity(), type); 512 case "securityDefinitions" -> toType(getSecurityDefinitions(), type); 513 case "swagger" -> toType(getSwagger(), type); 514 case "tags" -> toType(getTags(), type); 515 default -> super.get(property, type); 516 }; 517 } 518 519 /** 520 * Bean property getter: <property>basePath</property>. 521 * 522 * <p> 523 * The base path on which the API is served, which is relative to the <c>host</c>. 524 * 525 * @return The property value, or <jk>null</jk> if it is not set. 526 */ 527 public String getBasePath() { return basePath; } 528 529 /** 530 * Bean property getter: <property>consumes</property>. 531 * 532 * <p> 533 * A list of MIME types the APIs can consume. 534 * 535 * @return The property value, or <jk>null</jk> if it is not set. 536 */ 537 public Set<MediaType> getConsumes() { return nie(consumes); } 538 539 /** 540 * Bean property getter: <property>definitions</property>. 541 * 542 * <p> 543 * An object to hold data types produced and consumed by operations. 544 * 545 * @return The property value, or <jk>null</jk> if it is not set. 546 */ 547 public Map<String,JsonMap> getDefinitions() { return nie(definitions); } 548 549 /** 550 * Bean property getter: <property>externalDocs</property>. 551 * 552 * <p> 553 * Additional external documentation. 554 * 555 * @return The property value, or <jk>null</jk> if it is not set. 556 */ 557 public ExternalDocumentation getExternalDocs() { return externalDocs; } 558 559 /** 560 * Bean property getter: <property>host</property>. 561 * 562 * <p> 563 * The host (name or IP) serving the API. 564 * 565 * @return The property value, or <jk>null</jk> if it is not set. 566 */ 567 public String getHost() { return host; } 568 569 /** 570 * Bean property getter: <property>info</property>. 571 * 572 * <p> 573 * Provides metadata about the API. 574 * 575 * @return The property value, or <jk>null</jk> if it is not set. 576 */ 577 public Info getInfo() { return info; } 578 579 /** 580 * Shortcut for calling <c>getPaths().get(path).get(operation);</c> 581 * 582 * @param path The path (e.g. <js>"/foo"</js>). Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 583 * @param operation The HTTP operation (e.g. <js>"get"</js>). Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 584 * @return The operation for the specified path and operation id, or <jk>null</jk> if it doesn't exist. 585 */ 586 public Operation getOperation(String path, String operation) { 587 reqnn("path", path); 588 reqnn("operation", operation); 589 return o(getPath(path)).map(x -> x.get(operation)).orElse(null); 590 } 591 592 /** 593 * Convenience method for calling <c>getPath(path).get(method).getParameter(in,name);</c> 594 * 595 * @param path The HTTP path. Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 596 * @param method The HTTP method. Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 597 * @param in The parameter type. Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 598 * @param name The parameter name. Can be <jk>null</jk> for parameter type <c>body</c>. 599 * @return The parameter information or <jk>null</jk> if not found. 600 */ 601 public ParameterInfo getParameterInfo(String path, String method, String in, String name) { 602 reqnn("path", path); 603 reqnn("method", method); 604 reqnn("in", in); 605 return o(getPath(path)).map(x -> x.get(method)).map(x -> x.getParameter(in, name)).orElse(null); 606 } 607 608 /** 609 * Bean property getter: <property>parameters</property>. 610 * 611 * <p> 612 * An object to hold parameters that can be used across operations. 613 * 614 * @return The property value, or <jk>null</jk> if it is not set. 615 */ 616 public Map<String,ParameterInfo> getParameters() { return nie(parameters); } 617 618 /** 619 * Shortcut for calling <c>getPaths().get(path);</c> 620 * 621 * @param path The path (e.g. <js>"/foo"</js>). Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 622 * @return The operation map for the specified path, or <jk>null</jk> if it doesn't exist. 623 */ 624 public OperationMap getPath(String path) { 625 reqnn("path", path); 626 return o(getPaths()).map(x -> x.get(path)).orElse(null); 627 } 628 629 /** 630 * Bean property getter: <property>paths</property>. 631 * 632 * <p> 633 * The available paths and operations for the API. 634 * 635 * @return The property value, or <jk>null</jk> if it is not set. 636 */ 637 public Map<String,OperationMap> getPaths() { return nie(paths); } 638 639 /** 640 * Bean property getter: <property>produces</property>. 641 * 642 * <p> 643 * A list of MIME types the APIs can produce. 644 * 645 * @return The property value, or <jk>null</jk> if it is not set. 646 */ 647 public Set<MediaType> getProduces() { return nie(produces); } 648 649 /** 650 * Shortcut for calling <c>getPaths().get(path).get(operation).getResponse(status);</c> 651 * 652 * @param path The path (e.g. <js>"/foo"</js>). 653 * @param operation The HTTP operation (e.g. <js>"get"</js>). 654 * @param status The HTTP response status (e.g. <js>"200"</js>). 655 * @return The operation for the specified path and operation id, or <jk>null</jk> if it doesn't exist. 656 */ 657 public ResponseInfo getResponseInfo(String path, String operation, int status) { 658 return getResponseInfo(path, operation, String.valueOf(status)); 659 } 660 661 /** 662 * Shortcut for calling <c>getPaths().get(path).get(operation).getResponse(status);</c> 663 * 664 * @param path The path (e.g. <js>"/foo"</js>). Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 665 * @param operation The HTTP operation (e.g. <js>"get"</js>). Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 666 * @param status The HTTP response status (e.g. <js>"200"</js>). Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 667 * @return The operation for the specified path and operation id, or <jk>null</jk> if it doesn't exist. 668 */ 669 public ResponseInfo getResponseInfo(String path, String operation, String status) { 670 reqnn("path", path); 671 reqnn("operation", operation); 672 reqnn("status", status); 673 return o(getPath(path)).map(x -> x.get(operation)).map(x -> x.getResponse(status)).orElse(null); 674 } 675 676 /** 677 * Bean property getter: <property>responses</property>. 678 * 679 * <p> 680 * An object to hold responses that can be used across operations. 681 * 682 * @return The property value, or <jk>null</jk> if it is not set. 683 */ 684 public Map<String,ResponseInfo> getResponses() { return nie(responses); } 685 686 /** 687 * Bean property getter: <property>schemes</property>. 688 * 689 * <p> 690 * The transfer protocol of the API. 691 * 692 * @return The property value, or <jk>null</jk> if it is not set. 693 */ 694 public Set<String> getSchemes() { return nie(schemes); } 695 696 /** 697 * Bean property getter: <property>security</property>. 698 * 699 * <p> 700 * A declaration of which security schemes are applied for the API as a whole. 701 * 702 * @return The property value, or <jk>null</jk> if it is not set. 703 */ 704 public List<Map<String,List<String>>> getSecurity() { return nie(security); } 705 706 /** 707 * Bean property getter: <property>securityDefinitions</property>. 708 * 709 * <p> 710 * Security scheme definitions that can be used across the specification. 711 * 712 * @return The property value, or <jk>null</jk> if it is not set. 713 */ 714 public Map<String,SecurityScheme> getSecurityDefinitions() { return nie(securityDefinitions); } 715 716 /** 717 * Bean property getter: <property>swagger</property>. 718 * 719 * <p> 720 * Specifies the Swagger Specification version being used. 721 * 722 * @return The property value, or <jk>null</jk> if it is not set. 723 */ 724 public String getSwagger() { return swagger; } 725 726 /** 727 * Bean property getter: <property>tags</property>. 728 * 729 * <p> 730 * A list of tags used by the specification with additional metadata. 731 * 732 * @return The property value, or <jk>null</jk> if it is not set. 733 */ 734 public Set<Tag> getTags() { return nie(tags); } 735 736 @Override /* Overridden from SwaggerElement */ 737 public Set<String> keySet() { 738 // @formatter:off 739 var s = stb(String.class) 740 .addIf(nn(basePath), "basePath") 741 .addIf(ine(consumes), "consumes") 742 .addIf(ine(definitions), "definitions") 743 .addIf(nn(externalDocs), "externalDocs") 744 .addIf(nn(host), "host") 745 .addIf(nn(info), "info") 746 .addIf(ine(parameters), "parameters") 747 .addIf(ine(paths), "paths") 748 .addIf(ine(produces), "produces") 749 .addIf(ine(responses), "responses") 750 .addIf(ine(schemes), "schemes") 751 .addIf(ine(security), "security") 752 .addIf(ine(securityDefinitions), "securityDefinitions") 753 .addIf(nn(swagger), "swagger") 754 .addIf(ine(tags), "tags") 755 .build(); 756 // @formatter:on 757 return new MultiSet<>(s, super.keySet()); 758 } 759 760 @SuppressWarnings({ 761 "rawtypes", // Raw types necessary for generic type handling 762 "unchecked" // Type erasure requires unchecked casts in generic type conversions 763 }) 764 @Override /* Overridden from SwaggerElement */ 765 public Swagger set(String property, Object value) { 766 reqnn("property", property); 767 return switch (property) { 768 case "basePath" -> setBasePath(s(value)); 769 case "consumes" -> setConsumes(toListBuilder(value, MediaType.class).sparse().build()); 770 case "definitions" -> setDefinitions(toMapBuilder(value, String.class, JsonMap.class).sparse().build()); 771 case "externalDocs" -> setExternalDocs(toType(value, ExternalDocumentation.class)); 772 case "host" -> setHost(s(value)); 773 case "info" -> setInfo(toType(value, Info.class)); 774 case "parameters" -> setParameters(toMapBuilder(value, String.class, ParameterInfo.class).sparse().build()); 775 case "paths" -> setPaths(toMapBuilder(value, String.class, OperationMap.class).sparse().build()); 776 case "produces" -> setProduces(toListBuilder(value, MediaType.class).sparse().build()); 777 case "responses" -> setResponses(toMapBuilder(value, String.class, ResponseInfo.class).sparse().build()); 778 case "schemes" -> setSchemes(toListBuilder(value, String.class).sparse().build()); 779 case "security" -> setSecurity((List)toListBuilder(value, MapOfStringLists.class).sparse().build()); 780 case "securityDefinitions" -> setSecurityDefinitions(toMapBuilder(value, String.class, SecurityScheme.class).sparse().build()); 781 case "swagger" -> setSwagger(s(value)); 782 case "tags" -> setTags(toListBuilder(value, Tag.class).sparse().build()); 783 default -> { 784 super.set(property, value); 785 yield this; 786 } 787 }; 788 } 789 790 /** 791 * Bean property setter: <property>basePath</property>. 792 * 793 * <p> 794 * The base path on which the API is served, which is relative to the <c>host</c>. 795 * 796 * @param value 797 * The new value for this property. 798 * <br>If it is not included, the API is served directly under the <c>host</c>. 799 * <br>The value MUST start with a leading slash (/). 800 * <br>The <c>basePath</c> does not support <a class="doclink" href="https://swagger.io/specification/v2#pathTemplating">path templating</a>. 801 * <br>Can be <jk>null</jk> to unset the property. 802 * @return This object. 803 */ 804 public Swagger setBasePath(String value) { 805 basePath = value; 806 return this; 807 } 808 809 /** 810 * Bean property setter: <property>consumes</property>. 811 * 812 * <p> 813 * A list of MIME types the APIs can consume. 814 * 815 * @param value 816 * The new value for this property. 817 * <br>Value MUST be as described under <a class="doclink" href="https://swagger.io/specification#mimeTypes">Swagger Mime Types</a>. 818 * <br>Can be <jk>null</jk> to unset the property. 819 * @return This object. 820 */ 821 public Swagger setConsumes(Collection<MediaType> value) { 822 consumes.clear(); 823 if (nn(value)) 824 consumes.addAll(value); 825 return this; 826 } 827 828 /** 829 * Bean property fluent setter: <property>consumes</property>. 830 * 831 * <p> 832 * A list of MIME types the APIs can consume. 833 * 834 * @param value 835 * The values to set on this property. 836 * @return This object. 837 */ 838 public Swagger setConsumes(MediaType...value) { 839 setConsumes(stb(MediaType.class).sparse().add(value).build()); 840 return this; 841 } 842 843 /** 844 * Bean property setter: <property>definitions</property>. 845 * 846 * <p> 847 * An object to hold data types produced and consumed by operations. 848 * 849 * @param value 850 * The new value for this property. 851 * <br>Can be <jk>null</jk> to unset the property. 852 * @return This object. 853 */ 854 public Swagger setDefinitions(Map<String,JsonMap> value) { 855 definitions.clear(); 856 if (nn(value)) 857 definitions.putAll(value); 858 return this; 859 } 860 861 /** 862 * Bean property setter: <property>externalDocs</property>. 863 * 864 * <p> 865 * Additional external documentation. 866 * 867 * @param value 868 * The new value for this property. 869 * <br>Can be <jk>null</jk> to unset the property. 870 * @return This object. 871 */ 872 public Swagger setExternalDocs(ExternalDocumentation value) { 873 externalDocs = value; 874 return this; 875 } 876 877 /** 878 * Bean property setter: <property>host</property>. 879 * 880 * <p> 881 * The host (name or IP) serving the API. 882 * 883 * @param value 884 * The new value for this property. 885 * <br>This MUST be the host only and does not include the scheme nor sub-paths. 886 * <br>It MAY include a port. 887 * <br>If the host is not included, the host serving the documentation is to be used (including the port). 888 * <br>The host does not support <a class="doclink" href="https://swagger.io/specification/v2#pathTemplating">path templating</a> 889 * <br>Can be <jk>null</jk> to unset the property. 890 * @return This object. 891 */ 892 public Swagger setHost(String value) { 893 host = value; 894 return this; 895 } 896 897 /** 898 * Bean property setter: <property>info</property>. 899 * 900 * <p> 901 * Provides metadata about the API. 902 * 903 * @param value 904 * The new value for this property. 905 * <br>Property value is required. 906 * <br>Can be <jk>null</jk> to unset the property. 907 * @return This object. 908 */ 909 public Swagger setInfo(Info value) { 910 info = value; 911 return this; 912 } 913 914 /** 915 * Bean property setter: <property>parameters</property>. 916 * 917 * <p> 918 * An object to hold parameters that can be used across operations. 919 * 920 * @param value 921 * The new value for this property. 922 * <br>Can be <jk>null</jk> to unset the property. 923 * @return This object. 924 */ 925 public Swagger setParameters(Map<String,ParameterInfo> value) { 926 parameters.clear(); 927 if (nn(value)) 928 parameters.putAll(value); 929 return this; 930 } 931 932 /** 933 * Bean property setter: <property>paths</property>. 934 * 935 * <p> 936 * The available paths and operations for the API. 937 * 938 * @param value 939 * The new value for this property. 940 * <br>Property value is required. 941 * <br>Can be <jk>null</jk> to unset the property. 942 * @return This object. 943 */ 944 public Swagger setPaths(Map<String,OperationMap> value) { 945 paths.clear(); 946 if (nn(value)) 947 paths.putAll(value); 948 return this; 949 } 950 951 /** 952 * Bean property setter: <property>produces</property>. 953 * 954 * <p> 955 * A list of MIME types the APIs can produce. 956 * 957 * @param value 958 * The new value for this property. 959 * <br>Value MUST be as described under <a class="doclink" href="https://swagger.io/specification#mimeTypes">Swagger Mime Types</a>. 960 * <br>Can be <jk>null</jk> to unset the property. 961 * @return This object. 962 */ 963 public Swagger setProduces(Collection<MediaType> value) { 964 produces.clear(); 965 if (nn(value)) 966 produces.addAll(value); 967 return this; 968 } 969 970 /** 971 * Bean property fluent setter: <property>produces</property>. 972 * 973 * <p> 974 * A list of MIME types the APIs can produce. 975 * 976 * @param value 977 * The new value for this property. 978 * @return This object. 979 */ 980 public Swagger setProduces(MediaType...value) { 981 setProduces(stb(MediaType.class).sparse().add(value).build()); 982 return this; 983 } 984 985 /** 986 * Bean property setter: <property>responses</property>. 987 * 988 * <p> 989 * An object to hold responses that can be used across operations. 990 * 991 * @param value 992 * The new value for this property. 993 * <br>Can be <jk>null</jk> to unset the property. 994 * @return This object. 995 */ 996 public Swagger setResponses(Map<String,ResponseInfo> value) { 997 responses.clear(); 998 if (nn(value)) 999 responses.putAll(value); 1000 return this; 1001 } 1002 1003 /** 1004 * Bean property setter: <property>schemes</property>. 1005 * 1006 * <p> 1007 * The transfer protocol of the API. 1008 * 1009 * @param value 1010 * The new value for this property. 1011 * <br>Valid values: 1012 * <ul> 1013 * <li><js>"http"</js> 1014 * <li><js>"https"</js> 1015 * <li><js>"ws"</js> 1016 * <li><js>"wss"</js> 1017 * </ul> 1018 * <br>Can be <jk>null</jk> to unset the property. 1019 * @return This object. 1020 */ 1021 public Swagger setSchemes(Collection<String> value) { 1022 schemes.clear(); 1023 if (nn(value)) 1024 schemes.addAll(value); 1025 return this; 1026 } 1027 1028 /** 1029 * Bean property fluent setter: <property>schemes</property>. 1030 * 1031 * <p> 1032 * The transfer protocol of the API. 1033 * 1034 * @param value 1035 * The new value for this property. 1036 * <br>Strings can be JSON arrays. 1037 * @return This object. 1038 */ 1039 public Swagger setSchemes(String...value) { 1040 setSchemes(stb(String.class).sparse().addJson(value).build()); 1041 return this; 1042 } 1043 1044 /** 1045 * Bean property setter: <property>security</property>. 1046 * 1047 * <p> 1048 * A declaration of which security schemes are applied for the API as a whole. 1049 * 1050 * @param value 1051 * The new value for this property. 1052 * <br>Can be <jk>null</jk> to unset the property. 1053 * @return This object. 1054 */ 1055 public Swagger setSecurity(Collection<Map<String,List<String>>> value) { 1056 security.clear(); 1057 if (nn(value)) 1058 security.addAll(value); 1059 return this; 1060 } 1061 1062 /** 1063 * Bean property setter: <property>securityDefinitions</property>. 1064 * 1065 * <p> 1066 * Security scheme definitions that can be used across the specification. 1067 * 1068 * @param value 1069 * The new value for this property. 1070 * <br>Can be <jk>null</jk> to unset the property. 1071 * @return This object. 1072 */ 1073 public Swagger setSecurityDefinitions(Map<String,SecurityScheme> value) { 1074 securityDefinitions.clear(); 1075 if (nn(value)) 1076 securityDefinitions.putAll(value); 1077 return this; 1078 } 1079 1080 /** 1081 * Bean property setter: <property>swagger</property>. 1082 * 1083 * <p> 1084 * Specifies the Swagger Specification version being used. 1085 * 1086 * @param value 1087 * The new value for this property. 1088 * <br>Property value is required. 1089 * <br>Can be <jk>null</jk> to unset the property. 1090 * @return This object. 1091 */ 1092 public Swagger setSwagger(String value) { 1093 swagger = value; 1094 return this; 1095 } 1096 1097 /** 1098 * Bean property setter: <property>tags</property>. 1099 * 1100 * <p> 1101 * A list of tags used by the specification with additional metadata. 1102 * 1103 * @param value 1104 * The new value for this property. 1105 * <br>The order of the tags can be used to reflect on their order by the parsing tools. 1106 * <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. 1107 * <br>The tags that are not declared may be organized randomly or based on the tools' logic. 1108 * <br>Each tag name in the list MUST be unique. 1109 * <br>Can be <jk>null</jk> to unset the property. 1110 * @return This object. 1111 */ 1112 public Swagger setTags(Collection<Tag> value) { 1113 tags.clear(); 1114 if (nn(value)) 1115 tags.addAll(value); 1116 return this; 1117 } 1118 1119 /** 1120 * Bean property setter: <property>tags</property>. 1121 * 1122 * <p> 1123 * A list of tags used by the specification with additional metadata. 1124 * 1125 * @param value 1126 * The new value for this property. 1127 * <br>The order of the tags can be used to reflect on their order by the parsing tools. 1128 * <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. 1129 * <br>The tags that are not declared may be organized randomly or based on the tools' logic. 1130 * <br>Each tag name in the list MUST be unique. 1131 * <br>Ignored if <jk>null</jk>. 1132 * @return This object. 1133 */ 1134 public Swagger setTags(Tag...value) { 1135 setTags(stb(Tag.class).sparse().add(value).build()); 1136 return this; 1137 } 1138 1139 /** 1140 * Sets strict mode on this bean. 1141 * 1142 * @return This object. 1143 */ 1144 @Override 1145 public Swagger strict() { 1146 super.strict(); 1147 return this; 1148 } 1149 1150 /** 1151 * Sets strict mode on this bean. 1152 * 1153 * @param value 1154 * The new value for this property. 1155 * <br>Non-boolean values will be converted to boolean using <code>Boolean.<jsm>valueOf</jsm>(value.toString())</code>. 1156 * <br>Can be <jk>null</jk> (interpreted as <jk>false</jk>). 1157 * @return This object. 1158 */ 1159 @Override 1160 public Swagger strict(Object value) { 1161 super.strict(value); 1162 return this; 1163 } 1164 1165 @Override /* Overridden from Object */ 1166 public String toString() { 1167 return Json.of(this); 1168 } 1169}