001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.bean.openapi3; 018 019import static org.apache.juneau.commons.utils.CollectionUtils.*; 020import static org.apache.juneau.bean.openapi3.OpenApiCopyUtils.*; 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.marshall.marshaller.*; 028 029/** 030 * Describes a single operation parameter. 031 * 032 * <p> 033 * The Parameter Object describes a single parameter used in an API operation. Parameters can be passed in various 034 * locations including the path, query string, headers, or cookies. Each parameter has a name, location, and schema 035 * that defines its type and constraints. 036 * 037 * <h5 class='section'>OpenAPI Specification:</h5> 038 * <p> 039 * The Parameter Object is composed of the following fields: 040 * <ul class='spaced-list'> 041 * <li><c>name</c> (string, REQUIRED) - The name of the parameter 042 * <li><c>in</c> (string, REQUIRED) - The location of the parameter. Possible values: <js>"query"</js>, <js>"header"</js>, <js>"path"</js>, or <js>"cookie"</js> 043 * <li><c>description</c> (string) - A brief description of the parameter (CommonMark syntax may be used) 044 * <li><c>required</c> (boolean) - Determines whether this parameter is mandatory (must be <jk>true</jk> if <c>in</c> is <js>"path"</js>) 045 * <li><c>deprecated</c> (boolean) - Specifies that a parameter is deprecated 046 * <li><c>allowEmptyValue</c> (boolean) - Sets the ability to pass empty-valued parameters (valid only for <js>"query"</js> parameters) 047 * <li><c>style</c> (string) - Describes how the parameter value will be serialized 048 * <li><c>explode</c> (boolean) - When true, parameter values of type array or object generate separate parameters for each value 049 * <li><c>allowReserved</c> (boolean) - Determines whether the parameter value should allow reserved characters 050 * <li><c>schema</c> ({@link SchemaInfo}) - The schema defining the type used for the parameter 051 * <li><c>example</c> (any) - Example of the parameter's potential value 052 * <li><c>examples</c> (map of {@link Example}) - Examples of the parameter's potential value 053 * </ul> 054 * 055 * <h5 class='section'>Example:</h5> 056 * <p class='bjava'> 057 * <jc>// Create a query parameter</jc> 058 * Parameter <jv>param</jv> = <jk>new</jk> Parameter() 059 * .setName(<js>"status"</js>) 060 * .setIn(<js>"query"</js>) 061 * .setDescription(<js>"Status values to filter by"</js>) 062 * .setRequired(<jk>false</jk>) 063 * .setSchema( 064 * <jk>new</jk> SchemaInfo() 065 * .setType(<js>"array"</js>) 066 * .setItems( 067 * <jk>new</jk> Items().setType(<js>"string"</js>) 068 * ) 069 * ) 070 * .setStyle(<js>"form"</js>) 071 * .setExplode(<jk>true</jk>); 072 * </p> 073 * 074 * <h5 class='section'>See Also:</h5><ul> 075 * <li class='link'><a class="doclink" href="https://spec.openapis.org/oas/v3.0.0#parameter-object">OpenAPI Specification > Parameter Object</a> 076 * <li class='link'><a class="doclink" href="https://swagger.io/docs/specification/describing-parameters/">OpenAPI Describing Parameters</a> 077 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanOpenApi3">juneau-bean-openapi-v3</a> 078 * </ul> 079 */ 080@SuppressWarnings({ 081 "java:S1192" // Duplicated literals (argument/property names) read more clearly inline than as constants 082}) 083public class Parameter extends OpenApiElement { 084 085 private static final String[] VALID_IN = { "query", "header", "path", "cookie" }; 086 private static final String[] VALID_STYLES = { "matrix", "label", "form", "simple", "spaceDelimited", "pipeDelimited", "deepObject" }; 087 088 private String name; 089 private String in; 090 private String description; 091 private String style; 092 private Boolean required; 093 private Boolean deprecated; 094 private Boolean allowEmptyValue; 095 private Boolean explode; 096 private Boolean allowReserved; 097 private SchemaInfo schema; 098 private Object example; 099 private Map<String,Example> examples; 100 101 /** 102 * Default constructor. 103 */ 104 public Parameter() {} 105 106 /** 107 * Copy constructor. 108 * 109 * @param copyFrom The object to copy. 110 */ 111 public Parameter(Parameter copyFrom) { 112 super(copyFrom); 113 this.name = copyFrom.name; 114 this.in = copyFrom.in; 115 this.description = copyFrom.description; 116 this.style = copyFrom.style; 117 this.required = copyFrom.required; 118 this.deprecated = copyFrom.deprecated; 119 this.allowEmptyValue = copyFrom.allowEmptyValue; 120 this.explode = copyFrom.explode; 121 this.allowReserved = copyFrom.allowReserved; 122 this.schema = copyOf(copyFrom.schema); 123 this.example = copyFrom.example; 124 this.examples = copyOf(copyFrom.examples, Example::copy); 125 } 126 127 /** 128 * Makes a copy of this object. 129 * 130 * @return A new copy of this object. 131 */ 132 public Parameter copy() { 133 return new Parameter(this); 134 } 135 136 @Override /* Overridden from OpenApiElement */ 137 public <T> T get(String property, Class<T> type) { 138 reqnn("property", property); 139 return switch (property) { 140 case "name" -> toType(getName(), type); 141 case "in" -> toType(getIn(), type); 142 case "description" -> toType(getDescription(), type); 143 case "required" -> toType(getRequired(), type); 144 case "deprecated" -> toType(getDeprecated(), type); 145 case "allowEmptyValue" -> toType(getAllowEmptyValue(), type); 146 case "style" -> toType(getStyle(), type); 147 case "explode" -> toType(getExplode(), type); 148 case "allowReserved" -> toType(getAllowReserved(), type); 149 case "schema" -> toType(getSchema(), type); 150 case "example" -> toType(getExample(), type); 151 case "examples" -> toType(getExamples(), type); 152 default -> super.get(property, type); 153 }; 154 } 155 156 /** 157 * Returns the allow empty value flag. 158 * 159 * @return The allow empty value flag, or <jk>null</jk> if not set. 160 */ 161 public Boolean getAllowEmptyValue() { return allowEmptyValue; } 162 163 /** 164 * Returns the allow reserved flag. 165 * 166 * @return The allow reserved flag, or <jk>null</jk> if not set. 167 */ 168 public Boolean getAllowReserved() { return allowReserved; } 169 170 /** 171 * Returns the deprecated flag. 172 * 173 * @return The deprecated flag, or <jk>null</jk> if not set. 174 */ 175 public Boolean getDeprecated() { return deprecated; } 176 177 /** 178 * Returns the description. 179 * 180 * @return The description, or <jk>null</jk> if not set. 181 */ 182 public String getDescription() { return description; } 183 184 /** 185 * Returns the example. 186 * 187 * @return The example, or <jk>null</jk> if not set. 188 */ 189 public Object getExample() { return example; } 190 191 /** 192 * Returns the examples map. 193 * 194 * @return The examples map, or <jk>null</jk> if not set. 195 */ 196 public Map<String,Example> getExamples() { return u(examples); } 197 198 /** 199 * Returns the explode flag. 200 * 201 * @return The explode flag, or <jk>null</jk> if not set. 202 */ 203 public Boolean getExplode() { return explode; } 204 205 /** 206 * Returns the parameter location. 207 * 208 * @return The parameter location, or <jk>null</jk> if not set. 209 */ 210 public String getIn() { return in; } 211 212 /** 213 * Returns the parameter name. 214 * 215 * @return The parameter name, or <jk>null</jk> if not set. 216 */ 217 public String getName() { return name; } 218 219 /** 220 * Returns the required flag. 221 * 222 * @return The required flag, or <jk>null</jk> if not set. 223 */ 224 public Boolean getRequired() { return required; } 225 226 /** 227 * Returns the schema. 228 * 229 * @return The schema, or <jk>null</jk> if not set. 230 */ 231 public SchemaInfo getSchema() { return schema; } 232 233 /** 234 * Returns the style. 235 * 236 * @return The style, or <jk>null</jk> if not set. 237 */ 238 public String getStyle() { return style; } 239 240 @Override /* Overridden from OpenApiElement */ 241 public Set<String> keySet() { 242 // @formatter:off 243 var s = stb(String.class) 244 .addIf(nn(allowEmptyValue), "allowEmptyValue") 245 .addIf(nn(allowReserved), "allowReserved") 246 .addIf(nn(deprecated), "deprecated") 247 .addIf(nn(description), "description") 248 .addIf(nn(example), "example") 249 .addIf(nn(examples), "examples") 250 .addIf(nn(explode), "explode") 251 .addIf(nn(in), "in") 252 .addIf(nn(name), "name") 253 .addIf(nn(required), "required") 254 .addIf(nn(schema), "schema") 255 .addIf(nn(style), "style") 256 .build(); 257 // @formatter:on 258 return new MultiSet<>(s, super.keySet()); 259 } 260 261 @Override /* Overridden from OpenApiElement */ 262 public Parameter set(String property, Object value) { 263 reqnn("property", property); 264 return switch (property) { 265 case "allowEmptyValue" -> setAllowEmptyValue(toType(value, Boolean.class)); 266 case "allowReserved" -> setAllowReserved(toType(value, Boolean.class)); 267 case "description" -> setDescription(s(value)); 268 case "deprecated" -> setDeprecated(toType(value, Boolean.class)); 269 case "example" -> setExample(value); 270 case "examples" -> setExamples(toMapBuilder(value, String.class, Example.class).sparse().build()); 271 case "explode" -> setExplode(toType(value, Boolean.class)); 272 case "in" -> setIn(s(value)); 273 case "name" -> setName(s(value)); 274 case "required" -> setRequired(toType(value, Boolean.class)); 275 case "schema" -> setSchema(toType(value, SchemaInfo.class)); 276 case "style" -> setStyle(s(value)); 277 default -> { 278 super.set(property, value); 279 yield this; 280 } 281 }; 282 } 283 284 /** 285 * Sets the allow empty value flag. 286 * 287 * @param value The new value for this property. 288 * @return This object. 289 */ 290 public Parameter setAllowEmptyValue(Boolean value) { 291 allowEmptyValue = value; 292 return this; 293 } 294 295 /** 296 * Sets the allow reserved flag. 297 * 298 * @param value The new value for this property. 299 * @return This object. 300 */ 301 public Parameter setAllowReserved(Boolean value) { 302 allowReserved = value; 303 return this; 304 } 305 306 /** 307 * Sets the deprecated flag. 308 * 309 * @param value The new value for this property. 310 * @return This object. 311 */ 312 public Parameter setDeprecated(Boolean value) { 313 deprecated = value; 314 return this; 315 } 316 317 /** 318 * Sets the description. 319 * 320 * @param value The new value for this property. 321 * @return This object. 322 */ 323 public Parameter setDescription(String value) { 324 description = value; 325 return this; 326 } 327 328 /** 329 * Sets the example. 330 * 331 * @param value The new value for this property. 332 * @return This object. 333 */ 334 public Parameter setExample(Object value) { 335 example = value; 336 return this; 337 } 338 339 /** 340 * Sets the examples map. 341 * 342 * @param value The new value for this property. 343 * @return This object. 344 */ 345 public Parameter setExamples(Map<String,Example> value) { 346 examples = value; 347 return this; 348 } 349 350 /** 351 * Sets the explode flag. 352 * 353 * @param value The new value for this property. 354 * @return This object. 355 */ 356 public Parameter setExplode(Boolean value) { 357 explode = value; 358 return this; 359 } 360 361 /** 362 * Sets the parameter location. 363 * 364 * @param value The new value for this property. 365 * @return This object. 366 */ 367 public Parameter setIn(String value) { 368 if (isStrict() && ! contains(value, VALID_IN)) 369 throw rex("Invalid value passed in to setIn(String). Value='%s', valid values=%s", value, Json5.of(VALID_IN)); 370 in = value; 371 return this; 372 } 373 374 /** 375 * Sets the parameter name. 376 * 377 * @param value The new value for this property. 378 * @return This object. 379 */ 380 public Parameter setName(String value) { 381 name = value; 382 return this; 383 } 384 385 /** 386 * Sets the required flag. 387 * 388 * @param value The new value for this property. 389 * @return This object. 390 */ 391 public Parameter setRequired(Boolean value) { 392 required = value; 393 return this; 394 } 395 396 /** 397 * Sets the schema. 398 * 399 * @param value The new value for this property. 400 * @return This object. 401 */ 402 public Parameter setSchema(SchemaInfo value) { 403 schema = value; 404 return this; 405 } 406 407 /** 408 * Sets the style. 409 * 410 * @param value The new value for this property. 411 * @return This object. 412 */ 413 public Parameter setStyle(String value) { 414 if (isStrict() && ! contains(value, VALID_STYLES)) 415 throw rex("Invalid value passed in to setStyle(String). Value='%s', valid values=%s", value, Json5.of(VALID_STYLES)); 416 style = value; 417 return this; 418 } 419 420 @Override /* Overridden from OpenApiElement */ 421 public Parameter strict() { 422 super.strict(); 423 return this; 424 } 425 426 @Override /* Overridden from OpenApiElement */ 427 public Parameter strict(Object value) { 428 super.strict(value); 429 return this; 430 } 431}