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.openapi3; 014 015import static org.apache.juneau.common.internal.StringUtils.*; 016import static org.apache.juneau.internal.CollectionUtils.*; 017import static org.apache.juneau.internal.ConverterUtils.*; 018 019import org.apache.juneau.annotation.*; 020import org.apache.juneau.dto.swagger.Swagger; 021import org.apache.juneau.internal.*; 022 023import java.util.*; 024 025/** 026 * Describes a single HTTP header. 027 * 028 * <h5 class='section'>Example:</h5> 029 * <p class='bcode'> 030 * <jc>// Construct using SwaggerBuilder.</jc> 031 * HeaderInfo x = <jsm>headerInfo</jsm>(<js>"integer"</js>).description(<js>"The number of allowed requests in the current period"</js>); 032 * 033 * <jc>// Serialize using JsonSerializer.</jc> 034 * String json = JsonSerializer.<jsf>DEFAULT</jsf>.toString(x); 035 * 036 * <jc>// Or just use toString() which does the same as above.</jc> 037 * String json = x.toString(); 038 * </p> 039 * <p class='bcode'> 040 * <jc>// Output</jc> 041 * { 042 * <js>"description"</js>: <js>"The number of allowed requests in the current period"</js>, 043 * <js>"type"</js>: <js>"integer"</js> 044 * } 045 * </p> 046 */ 047@Bean(properties="description,explode,deprecated,allowEmptyValue,allowReserved,schema,example,examples,$ref,*") 048@SuppressWarnings({"unchecked"}) 049@FluentSetters 050public class HeaderInfo extends OpenApiElement { 051 052 private String 053 description, 054 ref; 055 private Boolean 056 required, 057 explode, 058 deprecated, 059 allowEmptyValue, 060 allowReserved; 061 private SchemaInfo schema; 062 private Object example; 063 private Map<String,Example> examples; 064 065 066 /** 067 * Default constructor. 068 */ 069 public HeaderInfo() {} 070 071 /** 072 * Copy constructor. 073 * 074 * @param copyFrom The object to copy. 075 */ 076 public HeaderInfo(HeaderInfo copyFrom) { 077 super(copyFrom); 078 079 this.description = copyFrom.description; 080 this.example = copyFrom.example; 081 this.allowEmptyValue = copyFrom.allowEmptyValue; 082 this.schema = copyFrom.schema; 083 this.allowReserved = copyFrom.allowReserved; 084 this.required = copyFrom.required; 085 this.ref = copyFrom.ref; 086 this.explode = copyFrom.explode; 087 this.deprecated = copyFrom.deprecated; 088 if (copyFrom.examples == null) 089 this.examples = null; 090 else 091 this.examples = new LinkedHashMap<>(); 092 for (Map.Entry<String,Example> e : copyFrom.examples.entrySet()) 093 this.examples.put(e.getKey(), e.getValue().copy()); 094 } 095 096 /** 097 * Make a deep copy of this object. 098 * 099 * @return A deep copy of this object. 100 */ 101 public HeaderInfo copy() { 102 return new HeaderInfo(this); 103 } 104 105 @Override /* OpenApiElement */ 106 protected HeaderInfo strict() { 107 super.strict(); 108 return this; 109 } 110 111 /** 112 * Bean property getter: <property>description</property>. 113 * 114 * <p> 115 * A short description of the header. 116 * 117 * @return The property value, or <jk>null</jk> if it is not set. 118 */ 119 public String getDescription() { 120 return description; 121 } 122 123 /** 124 * Bean property setter: <property>description</property>. 125 * 126 * <p> 127 * A short description of the header. 128 * 129 * @param value 130 * The new value for this property. 131 * <br>Can be <jk>null</jk> to unset the property. 132 * @return This object 133 */ 134 public HeaderInfo setDescription(String value) { 135 description = value; 136 return this; 137 } 138 139 /** 140 * Bean property getter: <property>required</property>. 141 * 142 * <p> 143 * The type of the object. 144 * 145 * @return The property value, or <jk>null</jk> if it is not set. 146 */ 147 public Boolean getRequired() { 148 return required; 149 } 150 151 /** 152 * Bean property setter: <property>required</property>. 153 * 154 * <p> 155 * The type of the object. 156 * 157 * @param value 158 * The new value for this property. 159 * <br>Property value is required. 160 * <br>Valid values: 161 * <ul> 162 * <li><js>"string"</js> 163 * <li><js>"number"</js> 164 * <li><js>"integer"</js> 165 * <li><js>"boolean"</js> 166 * <li><js>"array"</js> 167 * </ul> 168 * @return This object 169 */ 170 public HeaderInfo setRequired(Boolean value) { 171 required = value; 172 return this; 173 } 174 175 /** 176 * Bean property getter: <property>required</property>. 177 * 178 * <p> 179 * The type of the object. 180 * 181 * @return The property value, or <jk>null</jk> if it is not set. 182 */ 183 public Boolean getExplode() { 184 return explode; 185 } 186 187 /** 188 * Bean property setter: <property>explode</property>. 189 * 190 * <p> 191 * The type of the object. 192 * 193 * @param value 194 * The new value for this property. 195 * @return This object 196 */ 197 public HeaderInfo setExplode(Boolean value) { 198 explode = value; 199 return this; 200 } 201 202 /** 203 * Bean property getter: <property>deprecated</property>. 204 * 205 * <p> 206 * The type of the object. 207 * 208 * @return The property value, or <jk>null</jk> if it is not set. 209 */ 210 public Boolean getDeprecated() { 211 return deprecated; 212 } 213 214 /** 215 * Bean property setter: <property>deprecated</property>. 216 * 217 * <p> 218 * The type of the object. 219 * 220 * @param value 221 * The new value for this property. 222 * @return This object 223 */ 224 public HeaderInfo setDeprecated(Boolean value) { 225 deprecated = value; 226 return this; 227 } 228 229 /** 230 * Bean property getter: <property>allowEmptyValue</property>. 231 * 232 * <p> 233 * The type of the object. 234 * 235 * @return The property value, or <jk>null</jk> if it is not set. 236 */ 237 public Boolean getAllowEmptyValue() { 238 return allowEmptyValue; 239 } 240 241 /** 242 * Bean property setter: <property>allowEmptyValue</property>. 243 * 244 * <p> 245 * The type of the object. 246 * 247 * @param value 248 * The new value for this property. 249 * @return This object 250 */ 251 public HeaderInfo setAllowEmptyValue(Boolean value) { 252 allowEmptyValue = value; 253 return this; 254 } 255 256 /** 257 * Bean property getter: <property>allowReserved</property>. 258 * 259 * <p> 260 * The type of the object. 261 * 262 * @return The property value, or <jk>null</jk> if it is not set. 263 */ 264 public Boolean getAllowReserved() { 265 return allowReserved; 266 } 267 268 /** 269 * Bean property setter: <property>allowReserved</property>. 270 * 271 * <p> 272 * The type of the object. 273 * 274 * @param value 275 * The new value for this property. 276 * @return This object 277 */ 278 public HeaderInfo setAllowReserved(Boolean value) { 279 allowReserved = value; 280 return this; 281 } 282 283 /** 284 * Bean property getter: <property>schema</property>. 285 * 286 * @return The property value, or <jk>null</jk> if it is not set. 287 */ 288 public SchemaInfo getSchema() { 289 return schema; 290 } 291 292 /** 293 * Bean property setter: <property>schema</property>. 294 * 295 * @param value 296 * The new value for this property. 297 * <br>Can be <jk>null</jk> to unset the property. 298 * @return This object 299 */ 300 public HeaderInfo setSchema(SchemaInfo value) { 301 schema = value; 302 return this; 303 } 304 305 /** 306 * Bean property getter: <property>$ref</property>. 307 * 308 * @return The property value, or <jk>null</jk> if it is not set. 309 */ 310 @Beanp("$ref") 311 public String getRef() { 312 return ref; 313 } 314 315 /** 316 * Bean property setter: <property>$ref</property>. 317 * 318 * @param value 319 * The new value for this property. 320 * <br>Can be <jk>null</jk> to unset the property. 321 * @return This object 322 */ 323 @Beanp("$ref") 324 public HeaderInfo setRef(String value) { 325 ref = value; 326 return this; 327 } 328 329 /** 330 * Bean property getter: <property>x-example</property>. 331 * 332 * @return The property value, or <jk>null</jk> if it is not set. 333 */ 334 @Beanp("x-example") 335 public Object getExample() { 336 return example; 337 } 338 339 /** 340 * Bean property setter: <property>examples</property>. 341 * 342 * @param value 343 * The new value for this property. 344 * <br>Can be <jk>null</jk> to unset the property. 345 * @return This object 346 */ 347 @Beanp("x-example") 348 public HeaderInfo setExample(Object value) { 349 example = value; 350 return this; 351 } 352 353 /** 354 * Bean property getter: <property>examples</property>. 355 * 356 * <p> 357 * The list of possible responses as they are returned from executing this operation. 358 * 359 * @return The property value, or <jk>null</jk> if it is not set. 360 */ 361 public Map<String,Example> getExamples() { 362 return examples; 363 } 364 365 /** 366 * Bean property setter: <property>headers</property>. 367 * 368 * <p> 369 * A list of examples that are sent with the response. 370 * 371 * @param value 372 * The new value for this property. 373 * <br>Can be <jk>null</jk> to unset the property. 374 * @return This object 375 */ 376 public HeaderInfo setExamples(Map<String,Example> value) { 377 examples = copyOf(value); 378 return this; 379 } 380 381 /** 382 * Adds a single value to the <property>examples</property> property. 383 * 384 * @param name The example name. 385 * @param example The example. 386 * @return This object 387 */ 388 public HeaderInfo addExample(String name, Example example) { 389 examples = mapBuilder(examples).sparse().add(name, example).build(); 390 return this; 391 } 392 393 // <FluentSetters> 394 395 // </FluentSetters> 396 397 @Override /* OpenApiElement */ 398 public <T> T get(String property, Class<T> type) { 399 if (property == null) 400 return null; 401 switch (property) { 402 case "description": return (T)getDescription(); 403 case "required": return toType(getRequired(), type); 404 case "explode": return toType(getExplode(), type); 405 case "deprecated": return toType(getDeprecated(), type); 406 case "allowEmptyValue": return toType(getAllowEmptyValue(), type); 407 case "allowReserved": return toType(getAllowReserved(), type); 408 case "$ref": return toType(getRef(), type); 409 case "schema": return toType(getSchema(), type); 410 case "x-example": return toType(getExample(), type); 411 case "examples": return toType(getExamples(), type); 412 default: return super.get(property, type); 413 } 414 } 415 416 @Override /* OpenApiElement */ 417 public HeaderInfo set(String property, Object value) { 418 if (property == null) 419 return this; 420 switch (property) { 421 case "description": return setDescription(stringify(value)); 422 case "required": return setRequired(toBoolean(value)); 423 case "explode": return setExplode(toBoolean(value)); 424 case "deprecated": return setDeprecated(toBoolean(value)); 425 case "allowEmptyValue": return setAllowEmptyValue(toBoolean(value)); 426 case "$ref": return setRef(stringify(value)); 427 case "schema": return setSchema(toType(value, SchemaInfo.class)); 428 case "x-example": return setExample(stringify(value)); 429 case "examples": return setExamples(mapBuilder(String.class,Example.class).sparse().addAny(value).build()); 430 default: 431 super.set(property, value); 432 return this; 433 } 434 } 435 436 @Override /* SwaggerElement */ 437 public Set<String> keySet() { 438 Set<String> s = setBuilder(String.class) 439 .addIf(description != null, "description") 440 .addIf(required != null, "required") 441 .addIf(explode != null, "explode") 442 .addIf(deprecated != null, "deprecated") 443 .addIf(allowEmptyValue != null, "allowEmptyValue") 444 .addIf(ref != null, "$ref") 445 .addIf(allowReserved != null, "allowReserved") 446 .addIf(schema != null, "schema") 447 .addIf(example != null, "example") 448 .addIf(examples != null, "examples") 449 .build(); 450 return new MultiSet<>(s, super.keySet()); 451 452 } 453 454 /** 455 * Resolves any <js>"$ref"</js> attributes in this element. 456 * 457 * @param swagger The swagger document containing the definitions. 458 * @param refStack Keeps track of previously-visited references so that we don't cause recursive loops. 459 * @param maxDepth 460 * The maximum depth to resolve references. 461 * <br>After that level is reached, <code>$ref</code> references will be left alone. 462 * <br>Useful if you have very complex models and you don't want your swagger page to be overly-complex. 463 * @return 464 * This object with references resolved. 465 * <br>May or may not be the same object. 466 */ 467 public HeaderInfo resolveRefs(Swagger swagger, Deque<String> refStack, int maxDepth) { 468 469 if (ref != null) { 470 if (refStack.contains(ref) || refStack.size() >= maxDepth) 471 return this; 472 refStack.addLast(ref); 473 HeaderInfo r = swagger.findRef(ref, HeaderInfo.class).resolveRefs(swagger, refStack, maxDepth); 474 refStack.removeLast(); 475 return r; 476 } 477 return this; 478 } 479}