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