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.net.*; 024import java.util.*; 025 026import org.apache.juneau.*; 027import org.apache.juneau.common.utils.*; 028import org.apache.juneau.internal.*; 029 030/** 031 * A single encoding definition applied to a single schema property. 032 * 033 * <p> 034 * The Encoding Object is a single encoding definition applied to a single schema property. It allows you to define 035 * how a property should be serialized when it's part of a request or response body with a specific media type. 036 * 037 * <h5 class='section'>OpenAPI Specification:</h5> 038 * <p> 039 * The Encoding Object is composed of the following fields: 040 * <ul class='spaced-list'> 041 * <li><c>contentType</c> (string) - The Content-Type for encoding a specific property. Default value depends on the property type 042 * <li><c>headers</c> (map of {@link HeaderInfo}) - A map allowing additional information to be provided as headers 043 * <li><c>style</c> (string) - Describes how a specific property value will be serialized depending on its type 044 * <li><c>explode</c> (boolean) - When this is true, property values of type array or object generate separate parameters for each value 045 * <li><c>allowReserved</c> (boolean) - Determines whether the parameter value should allow reserved characters 046 * </ul> 047 * 048 * <h5 class='section'>Example:</h5> 049 * <p class='bcode'> 050 * <jc>// Construct using SwaggerBuilder.</jc> 051 * Encoding <jv>x</jv> = <jsm>encoding</jsm>() 052 * .setContentType(<js>"application/x-www-form-urlencoded"</js>) 053 * .setStyle(<js>"form"</js>) 054 * .setExplode(<jk>true</jk>); 055 * 056 * <jc>// Serialize using JsonSerializer.</jc> 057 * String <jv>json</jv> = Json.<jsm>from</jsm>(<jv>x</jv>); 058 * 059 * <jc>// Or just use toString() which does the same as above.</jc> 060 * <jv>json</jv> = <jv>x</jv>.toString(); 061 * </p> 062 * <p class='bcode'> 063 * <jc>// Output</jc> 064 * { 065 * <js>"contentType"</js>: <js>"application/x-www-form-urlencoded"</js>, 066 * <js>"style"</js>: <js>"form"</js>, 067 * <js>"explode"</js>: <jk>true</jk> 068 * } 069 * </p> 070 * 071 * <h5 class='section'>See Also:</h5><ul> 072 * <li class='link'><a class="doclink" href="https://spec.openapis.org/oas/v3.0.0#encoding-object">OpenAPI Specification > Encoding Object</a> 073 * <li class='link'><a class="doclink" href="https://swagger.io/docs/specification/describing-request-body/">OpenAPI Describing Request Body</a> 074 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanOpenApi3">juneau-bean-openapi-v3</a> 075 * </ul> 076 */ 077public class Encoding extends OpenApiElement{ 078 079 private String contentType, 080 style; 081 private Map<String,HeaderInfo> headers; 082 private Boolean explode, 083 allowReserved; 084 085 /** 086 * Default constructor. 087 */ 088 public Encoding() { } 089 090 /** 091 * Copy constructor. 092 * 093 * @param copyFrom The object to copy. 094 */ 095 public Encoding(Encoding copyFrom) { 096 super(copyFrom); 097 098 this.contentType = copyFrom.contentType; 099 this.style = copyFrom.style; 100 this.explode = copyFrom.explode; 101 this.allowReserved = copyFrom.allowReserved; 102 this.headers = copyOf(copyFrom.headers, HeaderInfo::copy); 103 } 104 105 /** 106 * Make a deep copy of this object. 107 * 108 * @return A deep copy of this object. 109 */ 110 public Encoding copy() { 111 return new Encoding(this); 112 } 113 114 @Override /* Overridden from OpenApiElement */ 115 protected Encoding strict() { 116 super.strict(); 117 return this; 118 } 119 120 @Override /* Overridden from OpenApiElement */ 121 public Encoding strict(Object value) { 122 super.strict(value); 123 return this; 124 } 125 126 /** 127 * Bean property getter: <property>contentType</property>. 128 * 129 * <p> 130 * The URL pointing to the contact information. 131 * 132 * @return The property value, or <jk>null</jk> if it is not set. 133 */ 134 public String getContentType() { 135 return contentType; 136 } 137 138 /** 139 * Bean property setter: <property>url</property>. 140 * 141 * <p> 142 * The value can be of any of the following types: {@link URI}, {@link URL}, {@link String}. 143 * <br>Strings must be valid URIs. 144 * 145 * <p> 146 * URIs defined by {@link UriResolver} can be used for values. 147 * 148 * @param value 149 * The new value for this property. 150 * <br>Can be <jk>null</jk> to unset the property. 151 * @return This object 152 */ 153 public Encoding setContentType(String value) { 154 contentType = value; 155 return this; 156 } 157 158 /** 159 * Bean property getter: <property>style</property>. 160 * 161 * @return The property value, or <jk>null</jk> if it is not set. 162 */ 163 public String getStyle() { 164 return style; 165 } 166 167 /** 168 * Bean property setter: <property>description</property>. 169 * 170 * @param value 171 * The new value for this property. 172 * <br>Can be <jk>null</jk> to unset the property. 173 * @return This object 174 */ 175 public Encoding setStyle(String value) { 176 style = value; 177 return this; 178 } 179 180 /** 181 * Bean property getter: <property>variables</property>. 182 * 183 * @return The property value, or <jk>null</jk> if it is not set. 184 */ 185 public Map<String, HeaderInfo> getHeaders() { 186 return headers; 187 } 188 189 /** 190 * Bean property setter: <property>variables</property>. 191 * 192 * @param value 193 * The new value for this property. 194 * <br>Can be <jk>null</jk> to unset the property. 195 * @return This object 196 */ 197 public Encoding setHeaders(Map<String, HeaderInfo> value) { 198 headers = copyOf(value); 199 return this; 200 } 201 202 /** 203 * Adds one or more values to the <property>headers</property> property. 204 * 205 * @param key The mapping key. Must not be <jk>null</jk>. 206 * @param value 207 * The values to add to this property. 208 * <br>Must not be <jk>null</jk>. 209 * @return This object 210 */ 211 public Encoding addHeader(String key, HeaderInfo value) { 212 assertArgNotNull("key", key); 213 assertArgNotNull("value", value); 214 headers = mapBuilder(headers).sparse().add(key, value).build(); 215 return this; 216 } 217 218 /** 219 * Bean property getter: <property>required</property>. 220 * 221 * <p> 222 * The type of the object. 223 * 224 * @return The property value, or <jk>null</jk> if it is not set. 225 */ 226 public Boolean getExplode() { 227 return explode; 228 } 229 230 /** 231 * Bean property setter: <property>explode</property>. 232 * 233 * <p> 234 * The type of the object. 235 * 236 * @param value 237 * The new value for this property. 238 * <br>Property value is required. 239 * <br>Can be <jk>null</jk> to unset the property. 240 * @return This object 241 */ 242 public Encoding setExplode(Boolean value) { 243 explode = value; 244 return this; 245 } 246 247 /** 248 * Bean property getter: <property>required</property>. 249 * 250 * <p> 251 * The type of the object. 252 * 253 * @return The property value, or <jk>null</jk> if it is not set. 254 */ 255 public Boolean getAllowReserved() { 256 return allowReserved; 257 } 258 259 /** 260 * Bean property setter: <property>explode</property>. 261 * 262 * <p> 263 * The type of the object. 264 * 265 * @param value 266 * The new value for this property. 267 * <br>Property value is required. 268 * <br>Can be <jk>null</jk> to unset the property. 269 * @return This object 270 */ 271 public Encoding setAllowReserved(Boolean value) { 272 allowReserved = value; 273 return this; 274 } 275 276 @Override /* Overridden from OpenApiElement */ 277 public <T> T get(String property, Class<T> type) { 278 assertArgNotNull("property", property); 279 return switch (property) { 280 case "contentType" -> toType(getContentType(), type); 281 case "style" -> toType(getStyle(), type); 282 case "headers" -> toType(getHeaders(), type); 283 case "explode" -> toType(getExplode(), type); 284 case "allowReserved" -> toType(getAllowReserved(), type); 285 default -> super.get(property, type); 286 }; 287 } 288 289 @Override /* Overridden from OpenApiElement */ 290 public Encoding set(String property, Object value) { 291 assertArgNotNull("property", property); 292 return switch (property) { 293 case "allowReserved" -> setAllowReserved(toBoolean(value)); 294 case "contentType" -> setContentType(Utils.s(value)); 295 case "explode" -> setExplode(toBoolean(value)); 296 case "headers" -> setHeaders(mapBuilder(String.class, HeaderInfo.class).sparse().addAny(value).build()); 297 case "style" -> setStyle(Utils.s(value)); 298 default -> { 299 super.set(property, value); 300 yield this; 301 } 302 }; 303 } 304 305 @Override /* Overridden from OpenApiElement */ 306 public Set<String> keySet() { 307 var s = setBuilder(String.class) 308 .addIf(allowReserved != null, "allowReserved") 309 .addIf(contentType != null, "contentType") 310 .addIf(explode != null, "explode") 311 .addIf(headers != null, "headers") 312 .addIf(style != null, "style") 313 .build(); 314 return new MultiSet<>(s, super.keySet()); 315 } 316}