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.Utils.*; 022import static org.apache.juneau.internal.ConverterUtils.*; 023 024import java.net.*; 025import java.util.*; 026 027import org.apache.juneau.*; 028import org.apache.juneau.commons.collections.*; 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, style; 080 private Map<String,HeaderInfo> headers = map(); 081 private Boolean explode, allowReserved; 082 083 /** 084 * Default constructor. 085 */ 086 public Encoding() {} 087 088 /** 089 * Copy constructor. 090 * 091 * @param copyFrom The object to copy. 092 */ 093 public Encoding(Encoding copyFrom) { 094 super(copyFrom); 095 096 this.contentType = copyFrom.contentType; 097 this.style = copyFrom.style; 098 this.explode = copyFrom.explode; 099 this.allowReserved = copyFrom.allowReserved; 100 if (nn(copyFrom.headers)) 101 headers.putAll(copyOf(copyFrom.headers, HeaderInfo::copy)); 102 } 103 104 /** 105 * Adds one or more values to the <property>headers</property> property. 106 * 107 * @param key The mapping key. Must not be <jk>null</jk>. 108 * @param value 109 * The values to add to this property. 110 * <br>Must not be <jk>null</jk>. 111 * @return This object 112 */ 113 public Encoding addHeader(String key, HeaderInfo value) { 114 assertArgNotNull("key", key); 115 assertArgNotNull("value", value); 116 headers.put(key, value); 117 return this; 118 } 119 120 /** 121 * Make a deep copy of this object. 122 * 123 * @return A deep copy of this object. 124 */ 125 public Encoding copy() { 126 return new Encoding(this); 127 } 128 129 @Override /* Overridden from OpenApiElement */ 130 public <T> T get(String property, Class<T> type) { 131 assertArgNotNull("property", property); 132 return switch (property) { 133 case "contentType" -> toType(getContentType(), type); 134 case "style" -> toType(getStyle(), type); 135 case "headers" -> toType(getHeaders(), type); 136 case "explode" -> toType(getExplode(), type); 137 case "allowReserved" -> toType(getAllowReserved(), type); 138 default -> super.get(property, type); 139 }; 140 } 141 142 /** 143 * Bean property getter: <property>required</property>. 144 * 145 * <p> 146 * The type of the object. 147 * 148 * @return The property value, or <jk>null</jk> if it is not set. 149 */ 150 public Boolean getAllowReserved() { return allowReserved; } 151 152 /** 153 * Bean property getter: <property>contentType</property>. 154 * 155 * <p> 156 * The URL pointing to the contact information. 157 * 158 * @return The property value, or <jk>null</jk> if it is not set. 159 */ 160 public String getContentType() { return contentType; } 161 162 /** 163 * Bean property getter: <property>required</property>. 164 * 165 * <p> 166 * The type of the object. 167 * 168 * @return The property value, or <jk>null</jk> if it is not set. 169 */ 170 public Boolean getExplode() { return explode; } 171 172 /** 173 * Bean property getter: <property>variables</property>. 174 * 175 * @return The property value, or <jk>null</jk> if it is not set. 176 */ 177 public Map<String,HeaderInfo> getHeaders() { return nullIfEmpty(headers); } 178 179 /** 180 * Bean property getter: <property>style</property>. 181 * 182 * @return The property value, or <jk>null</jk> if it is not set. 183 */ 184 public String getStyle() { return style; } 185 186 @Override /* Overridden from OpenApiElement */ 187 public Set<String> keySet() { 188 // @formatter:off 189 var s = setb(String.class) 190 .addIf(nn(allowReserved), "allowReserved") 191 .addIf(nn(contentType), "contentType") 192 .addIf(nn(explode), "explode") 193 .addIf(ne(headers), "headers") 194 .addIf(nn(style), "style") 195 .build(); 196 // @formatter:on 197 return new MultiSet<>(s, super.keySet()); 198 } 199 200 @Override /* Overridden from OpenApiElement */ 201 public Encoding set(String property, Object value) { 202 assertArgNotNull("property", property); 203 return switch (property) { 204 case "allowReserved" -> setAllowReserved(toBoolean(value)); 205 case "contentType" -> setContentType(s(value)); 206 case "explode" -> setExplode(toBoolean(value)); 207 case "headers" -> setHeaders(toMapBuilder(value, String.class, HeaderInfo.class).sparse().build()); 208 case "style" -> setStyle(s(value)); 209 default -> { 210 super.set(property, value); 211 yield this; 212 } 213 }; 214 } 215 216 /** 217 * Bean property setter: <property>explode</property>. 218 * 219 * <p> 220 * The type of the object. 221 * 222 * @param value 223 * The new value for this property. 224 * <br>Property value is required. 225 * <br>Can be <jk>null</jk> to unset the property. 226 * @return This object 227 */ 228 public Encoding setAllowReserved(Boolean value) { 229 allowReserved = value; 230 return this; 231 } 232 233 /** 234 * Bean property setter: <property>url</property>. 235 * 236 * <p> 237 * The value can be of any of the following types: {@link URI}, {@link URL}, {@link String}. 238 * <br>Strings must be valid URIs. 239 * 240 * <p> 241 * URIs defined by {@link UriResolver} can be used for values. 242 * 243 * @param value 244 * The new value for this property. 245 * <br>Can be <jk>null</jk> to unset the property. 246 * @return This object 247 */ 248 public Encoding setContentType(String value) { 249 contentType = value; 250 return this; 251 } 252 253 /** 254 * Bean property setter: <property>explode</property>. 255 * 256 * <p> 257 * The type of the object. 258 * 259 * @param value 260 * The new value for this property. 261 * <br>Property value is required. 262 * <br>Can be <jk>null</jk> to unset the property. 263 * @return This object 264 */ 265 public Encoding setExplode(Boolean value) { 266 explode = value; 267 return this; 268 } 269 270 /** 271 * Bean property setter: <property>variables</property>. 272 * 273 * @param value 274 * The new value for this property. 275 * <br>Can be <jk>null</jk> to unset the property. 276 * @return This object 277 */ 278 public Encoding setHeaders(Map<String,HeaderInfo> value) { 279 headers.clear(); 280 if (nn(value)) 281 headers.putAll(value); 282 return this; 283 } 284 285 /** 286 * Bean property setter: <property>description</property>. 287 * 288 * @param value 289 * The new value for this property. 290 * <br>Can be <jk>null</jk> to unset the property. 291 * @return This object 292 */ 293 public Encoding setStyle(String value) { 294 style = value; 295 return this; 296 } 297 298 @Override /* Overridden from OpenApiElement */ 299 public Encoding strict(Object value) { 300 super.strict(value); 301 return this; 302 } 303 304 @Override /* Overridden from OpenApiElement */ 305 protected Encoding strict() { 306 super.strict(); 307 return this; 308 } 309}