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.AssertionUtils.*; 020import static org.apache.juneau.commons.utils.CollectionUtils.*; 021import static org.apache.juneau.commons.utils.ThrowableUtils.*; 022import static org.apache.juneau.commons.utils.Utils.*; 023import static org.apache.juneau.internal.ConverterUtils.*; 024 025import java.util.*; 026 027import org.apache.juneau.commons.collections.*; 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 @Override /* Overridden from OpenApiElement */ 128 public <T> T get(String property, Class<T> type) { 129 assertArgNotNull("property", property); 130 return switch (property) { 131 case "name" -> toType(getName(), type); 132 case "in" -> toType(getIn(), type); 133 case "description" -> toType(getDescription(), type); 134 case "required" -> toType(getRequired(), type); 135 case "deprecated" -> toType(getDeprecated(), type); 136 case "allowEmptyValue" -> toType(getAllowEmptyValue(), type); 137 case "style" -> toType(getStyle(), type); 138 case "explode" -> toType(getExplode(), type); 139 case "allowReserved" -> toType(getAllowReserved(), type); 140 case "schema" -> toType(getSchema(), type); 141 case "example" -> toType(getExample(), type); 142 case "examples" -> toType(getExamples(), type); 143 default -> super.get(property, type); 144 }; 145 } 146 147 /** 148 * Returns the allow empty value flag. 149 * 150 * @return The allow empty value flag. 151 */ 152 public Boolean getAllowEmptyValue() { return allowEmptyValue; } 153 154 /** 155 * Returns the allow reserved flag. 156 * 157 * @return The allow reserved flag. 158 */ 159 public Boolean getAllowReserved() { return allowReserved; } 160 161 /** 162 * Returns the deprecated flag. 163 * 164 * @return The deprecated flag. 165 */ 166 public Boolean getDeprecated() { return deprecated; } 167 168 /** 169 * Returns the description. 170 * 171 * @return The description. 172 */ 173 public String getDescription() { return description; } 174 175 /** 176 * Returns the example. 177 * 178 * @return The example. 179 */ 180 public Object getExample() { return example; } 181 182 /** 183 * Returns the examples map. 184 * 185 * @return The examples map. 186 */ 187 public Map<String,Example> getExamples() { return examples; } 188 189 /** 190 * Returns the explode flag. 191 * 192 * @return The explode flag. 193 */ 194 public Boolean getExplode() { return explode; } 195 196 /** 197 * Returns the parameter location. 198 * 199 * @return The parameter location. 200 */ 201 public String getIn() { return in; } 202 203 /** 204 * Returns the parameter name. 205 * 206 * @return The parameter name. 207 */ 208 public String getName() { return name; } 209 210 /** 211 * Returns the required flag. 212 * 213 * @return The required flag. 214 */ 215 public Boolean getRequired() { return required; } 216 217 /** 218 * Returns the schema. 219 * 220 * @return The schema. 221 */ 222 public SchemaInfo getSchema() { return schema; } 223 224 /** 225 * Returns the style. 226 * 227 * @return The style. 228 */ 229 public String getStyle() { return style; } 230 231 @Override /* Overridden from OpenApiElement */ 232 public Set<String> keySet() { 233 // @formatter:off 234 var s = setb(String.class) 235 .addIf(nn(allowEmptyValue), "allowEmptyValue") 236 .addIf(nn(allowReserved), "allowReserved") 237 .addIf(nn(deprecated), "deprecated") 238 .addIf(nn(description), "description") 239 .addIf(nn(example), "example") 240 .addIf(nn(examples), "examples") 241 .addIf(nn(explode), "explode") 242 .addIf(nn(in), "in") 243 .addIf(nn(name), "name") 244 .addIf(nn(required), "required") 245 .addIf(nn(schema), "schema") 246 .addIf(nn(style), "style") 247 .build(); 248 // @formatter:on 249 return new MultiSet<>(s, super.keySet()); 250 } 251 252 @Override /* Overridden from OpenApiElement */ 253 public Parameter set(String property, Object value) { 254 assertArgNotNull("property", property); 255 return switch (property) { 256 case "allowEmptyValue" -> setAllowEmptyValue(toType(value, Boolean.class)); 257 case "allowReserved" -> setAllowReserved(toType(value, Boolean.class)); 258 case "description" -> setDescription(s(value)); 259 case "deprecated" -> setDeprecated(toType(value, Boolean.class)); 260 case "example" -> setExample(value); 261 case "examples" -> setExamples(toMapBuilder(value, String.class, Example.class).sparse().build()); 262 case "explode" -> setExplode(toType(value, Boolean.class)); 263 case "in" -> setIn(s(value)); 264 case "name" -> setName(s(value)); 265 case "required" -> setRequired(toType(value, Boolean.class)); 266 case "schema" -> setSchema(toType(value, SchemaInfo.class)); 267 case "style" -> setStyle(s(value)); 268 default -> { 269 super.set(property, value); 270 yield this; 271 } 272 }; 273 } 274 275 /** 276 * Sets the allow empty value flag. 277 * 278 * @param value The new value for this property. 279 * @return This object. 280 */ 281 public Parameter setAllowEmptyValue(Boolean value) { 282 allowEmptyValue = value; 283 return this; 284 } 285 286 /** 287 * Sets the allow reserved flag. 288 * 289 * @param value The new value for this property. 290 * @return This object. 291 */ 292 public Parameter setAllowReserved(Boolean value) { 293 allowReserved = value; 294 return this; 295 } 296 297 /** 298 * Sets the deprecated flag. 299 * 300 * @param value The new value for this property. 301 * @return This object. 302 */ 303 public Parameter setDeprecated(Boolean value) { 304 deprecated = value; 305 return this; 306 } 307 308 /** 309 * Sets the description. 310 * 311 * @param value The new value for this property. 312 * @return This object. 313 */ 314 public Parameter setDescription(String value) { 315 description = value; 316 return this; 317 } 318 319 /** 320 * Sets the example. 321 * 322 * @param value The new value for this property. 323 * @return This object. 324 */ 325 public Parameter setExample(Object value) { 326 example = value; 327 return this; 328 } 329 330 /** 331 * Sets the examples map. 332 * 333 * @param value The new value for this property. 334 * @return This object. 335 */ 336 public Parameter setExamples(Map<String,Example> value) { 337 examples = value; 338 return this; 339 } 340 341 /** 342 * Sets the explode flag. 343 * 344 * @param value The new value for this property. 345 * @return This object. 346 */ 347 public Parameter setExplode(Boolean value) { 348 explode = value; 349 return this; 350 } 351 352 /** 353 * Sets the parameter location. 354 * 355 * @param value The new value for this property. 356 * @return This object. 357 */ 358 public Parameter setIn(String value) { 359 if (isStrict() && ! contains(value, VALID_IN)) 360 throw rex("Invalid value passed in to setIn(String). Value=''{0}'', valid values={1}", value, Json5.of(VALID_IN)); 361 in = value; 362 return this; 363 } 364 365 /** 366 * Sets the parameter name. 367 * 368 * @param value The new value for this property. 369 * @return This object. 370 */ 371 public Parameter setName(String value) { 372 name = value; 373 return this; 374 } 375 376 /** 377 * Sets the required flag. 378 * 379 * @param value The new value for this property. 380 * @return This object. 381 */ 382 public Parameter setRequired(Boolean value) { 383 required = value; 384 return this; 385 } 386 387 /** 388 * Sets the schema. 389 * 390 * @param value The new value for this property. 391 * @return This object. 392 */ 393 public Parameter setSchema(SchemaInfo value) { 394 schema = value; 395 return this; 396 } 397 398 /** 399 * Sets the style. 400 * 401 * @param value The new value for this property. 402 * @return This object. 403 */ 404 public Parameter setStyle(String value) { 405 if (isStrict() && ! contains(value, VALID_STYLES)) 406 throw rex("Invalid value passed in to setStyle(String). Value=''{0}'', valid values={1}", value, Json5.of(VALID_STYLES)); 407 style = value; 408 return this; 409 } 410 411 @Override /* Overridden from OpenApiElement */ 412 public Parameter strict() { 413 super.strict(); 414 return this; 415 } 416 417 @Override /* Overridden from OpenApiElement */ 418 public Parameter strict(Object value) { 419 super.strict(value); 420 return this; 421 } 422}