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