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.http.classic.header; 018 019import static org.apache.juneau.commons.utils.Shorts.*; 020 021import java.util.function.*; 022 023import org.apache.juneau.commons.httppart.*; 024import org.apache.juneau.marshall.httppart.*; 025import org.apache.juneau.marshall.oapi.*; 026import org.apache.juneau.marshall.serializer.*; 027 028/** 029 * <h5 class='section'>See Also:</h5><ul> 030 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestCommon">juneau-rest-common</a> 031 * </ul> 032 * 033 * @serial exclude 034 */ 035@SuppressWarnings({ 036 "java:S2160", // equals() inherited from BasicHeader compares name+value; serializer field affects rendering not identity 037 "java:S9149" // Public Juneau DSL factory; hiding parent of()/create() is intentional. 038}) 039public class SerializedHeader extends BasicHeader { 040 private static final long serialVersionUID = 1L; 041 042 /** 043 * Static creator. 044 * 045 * @param name The header name. 046 * @param value 047 * The POJO to serialize as the header value. 048 * <br>Can be <jk>null</jk>. The effect is implementation-dependent — see {@link HttpPartSerializerSession} and {@link HttpPartSchema}. 049 * @return A new header bean. Never <jk>null</jk>. 050 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 051 */ 052 public static SerializedHeader of(String name, Object value) { 053 return new SerializedHeader(name, value, null, null, false); 054 } 055 056 /** 057 * Static creator. 058 * 059 * @param name The HTTP header name name. 060 * @param value 061 * The POJO to serialize as the header value. 062 * @param serializer 063 * The serializer to use for serializing the value to a string value. 064 * <br>Can be <jk>null</jk>, in which case the value is converted directly to a string instead of being serialized. 065 * @param schema 066 * The schema object that defines the format of the output. 067 * <br>If <jk>null</jk>, defaults to the schema defined on the serializer. 068 * <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}. 069 * <br>Only used if serializer is schema-aware (e.g. {@link OpenApiSerializer}). 070 * <br>Can also be a {@link Supplier}. 071 * @param skipIfEmpty If value is a blank string, the value should return as <jk>null</jk>. 072 * @return A new header bean. Never <jk>null</jk>. 073 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 074 */ 075 public static SerializedHeader of(String name, Object value, HttpPartSerializerSession serializer, HttpPartSchema schema, boolean skipIfEmpty) { 076 return new SerializedHeader(name, value, serializer, schema, skipIfEmpty); 077 } 078 079 /** 080 * Static creator with delayed value. 081 * 082 * <p> 083 * Header value is re-evaluated on each call to {@link #getValue()}. 084 * 085 * @param name The header name. 086 * @param value 087 * The supplier of the POJO to serialize as the header value. 088 * <br>Can be <jk>null</jk>. The effect is implementation-dependent — see {@link HttpPartSerializerSession} and {@link HttpPartSchema}. 089 * @return A new header bean. Never <jk>null</jk>. 090 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 091 */ 092 public static SerializedHeader of(String name, Supplier<?> value) { 093 return new SerializedHeader(name, value, null, null, false); 094 } 095 096 /** 097 * Static creator with delayed value. 098 * 099 * <p> 100 * Header value is re-evaluated on each call to {@link #getValue()}. 101 * 102 * @param name The HTTP header name name. 103 * @param value 104 * The supplier of the POJO to serialize as the header value. 105 * @param serializer 106 * The serializer to use for serializing the value to a string value. 107 * <br>Can be <jk>null</jk>, in which case the value is converted directly to a string instead of being serialized. 108 * @param schema 109 * The schema object that defines the format of the output. 110 * <br>If <jk>null</jk>, defaults to the schema defined on the serializer. 111 * <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}. 112 * <br>Only used if serializer is schema-aware (e.g. {@link OpenApiSerializer}). 113 * <br>Can also be a {@link Supplier}. 114 * @param skipIfEmpty If value is a blank string, the value should return as <jk>null</jk>. 115 * @return A new header bean. Never <jk>null</jk>. 116 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 117 */ 118 public static SerializedHeader of(String name, Supplier<?> value, HttpPartSerializerSession serializer, HttpPartSchema schema, boolean skipIfEmpty) { 119 return new SerializedHeader(name, value, serializer, schema, skipIfEmpty); 120 } 121 122 private final transient Object value; 123 private final transient Supplier<Object> supplier; 124 private transient HttpPartSerializerSession serializer; 125 private transient HttpPartSchema schema = HttpPartSchema.DEFAULT; 126 private boolean skipIfEmpty; 127 128 /** 129 * Constructor. 130 * 131 * @param name The HTTP header name name. 132 * @param value The POJO to serialize to the parameter value. Can be <jk>null</jk>. The effect is implementation-dependent — see {@link HttpPartSerializerSession} and {@link HttpPartSchema}. 133 * @param serializer 134 * The serializer to use for serializing the value to a string value. 135 * <br>Can be <jk>null</jk>, in which case the value is converted directly to a string instead of being serialized. 136 * @param schema 137 * The schema object that defines the format of the output. 138 * <br>If <jk>null</jk>, defaults to the schema defined on the serializer. 139 * <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}. 140 * <br>Only used if serializer is schema-aware (e.g. {@link OpenApiSerializer}). 141 * <br>Can also be a {@link Supplier}. 142 * @param skipIfEmpty If value is a blank string, the value should return as <jk>null</jk>. 143 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 144 */ 145 @SuppressWarnings({ 146 "unchecked" // Type erasure requires cast for supplier 147 }) 148 public SerializedHeader(String name, Object value, HttpPartSerializerSession serializer, HttpPartSchema schema, boolean skipIfEmpty) { 149 super(name, null); 150 this.value = value instanceof Supplier ? null : value; 151 this.supplier = value instanceof Supplier ? (Supplier<Object>)value : null; 152 this.serializer = serializer; 153 this.schema = schema; 154 this.skipIfEmpty = skipIfEmpty; 155 } 156 157 /** 158 * Constructor with delayed value. 159 * 160 * <p> 161 * Header value is re-evaluated on each call to {@link #getValue()}. 162 * 163 * @param name The HTTP header name name. 164 * @param value The supplier of the POJO to serialize to the parameter value. Can be <jk>null</jk>. The effect is implementation-dependent — see {@link HttpPartSerializerSession} and {@link HttpPartSchema}. 165 * @param serializer 166 * The serializer to use for serializing the value to a string value. 167 * <br>Can be <jk>null</jk>, in which case the value is converted directly to a string instead of being serialized. 168 * @param schema 169 * The schema object that defines the format of the output. 170 * <br>If <jk>null</jk>, defaults to the schema defined on the serializer. 171 * <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}. 172 * <br>Only used if serializer is schema-aware (e.g. {@link OpenApiSerializer}). 173 * <br>Can also be a {@link Supplier}. 174 * @param skipIfEmpty If value is a blank string, the value should return as <jk>null</jk>. 175 * @throws IllegalArgumentException If name is <jk>null</jk> or empty. 176 */ 177 public SerializedHeader(String name, Supplier<Object> value, HttpPartSerializerSession serializer, HttpPartSchema schema, boolean skipIfEmpty) { 178 super(name, null); 179 this.value = null; 180 supplier = value; 181 this.serializer = serializer; 182 this.schema = schema; 183 this.skipIfEmpty = skipIfEmpty; 184 } 185 186 /** 187 * Copy constructor. 188 * 189 * @param copyFrom The object to copy. Must not be <jk>null</jk> or a {@link NullPointerException} is thrown. 190 */ 191 protected SerializedHeader(SerializedHeader copyFrom) { 192 super(copyFrom); 193 this.value = copyFrom.value; 194 this.supplier = copyFrom.supplier; 195 this.serializer = copyFrom.serializer == null ? serializer : copyFrom.serializer; 196 this.schema = copyFrom.schema == null ? schema : copyFrom.schema; 197 this.skipIfEmpty = copyFrom.skipIfEmpty; 198 } 199 200 /** 201 * Creates a copy of this object. 202 * 203 * @return A new copy of this object. 204 */ 205 @Override /* Overridden from BasicHeader */ 206 public SerializedHeader copy() { 207 return new SerializedHeader(this); 208 } 209 210 /** 211 * Copies this bean and sets the serializer and schema on it. 212 * 213 * @param serializer The new serializer for the bean. Can be <jk>null</jk> to leave the serializer unchanged. 214 * @param schema The new schema for the bean. Can be <jk>null</jk> to leave the schema unchanged. 215 * @return Either a new bean with the serializer set, or this bean if 216 * both values are <jk>null</jk> or the serializer and schema were already set. 217 */ 218 public SerializedHeader copyWith(HttpPartSerializerSession serializer, HttpPartSchema schema) { 219 if ((this.serializer == null && nn(serializer)) || (this.schema == null && nn(schema))) { 220 SerializedHeader h = copy(); 221 if (nn(serializer)) 222 h.serializer(serializer); 223 if (nn(schema)) 224 h.schema(schema); 225 return h; 226 } 227 return this; 228 } 229 230 @Override /* Overridden from NameValuePair */ 231 public String getValue() { 232 try { 233 Object v = value; 234 if (nn(supplier)) 235 v = supplier.get(); 236 HttpPartSchema schema2 = this.schema == null ? HttpPartSchema.DEFAULT : this.schema; 237 var def = schema2.getDefault(); 238 if (v == null && ((def == null && ! schema2.isRequired()) || (def == null && schema2.isAllowEmptyValue()))) 239 return null; 240 if (ie(s(v)) && skipIfEmpty && def == null) 241 return null; 242 return serializer == null ? s(v) : serializer.write(HttpPartType.HEADER, schema2, v); 243 } catch (SchemaValidationException e) { 244 throw rex(e, "Validation error on request %s parameter '%s'='%s'", HttpPartType.HEADER, getName(), value); 245 } catch (SerializeException e) { 246 throw rex(e, "Serialization error on request %s parameter '%s'", HttpPartType.HEADER, getName()); 247 } 248 } 249 250 /** 251 * Sets the schema object that defines the format of the output. 252 * 253 * @param value The new value for this property. Can be <jk>null</jk> to unset the property. 254 * @return This object. 255 */ 256 public SerializedHeader schema(HttpPartSchema value) { 257 schema = value; 258 return this; 259 } 260 261 /** 262 * Sets the serializer to use for serializing the value to a string value. 263 * 264 * @param value The new value for this property. Can be <jk>null</jk> (no-op). 265 * @return This object. 266 */ 267 public SerializedHeader serializer(HttpPartSerializer value) { 268 if (nn(value)) 269 return serializer(value.getPartSession()); 270 return this; 271 } 272 273 /** 274 * Sets the serializer to use for serializing the value to a string value. 275 * 276 * @param value The new value for this property. Can be <jk>null</jk> to unset the property. 277 * @return This object. 278 */ 279 public SerializedHeader serializer(HttpPartSerializerSession value) { 280 serializer = value; 281 return this; 282 } 283 284 /** 285 * Don't serialize this header if the value is <jk>null</jk> or an empty string. 286 * 287 * @return This object. 288 */ 289 public SerializedHeader skipIfEmpty() { 290 return skipIfEmpty(true); 291 } 292 293 /** 294 * Don't serialize this header if the value is <jk>null</jk> or an empty string. 295 * 296 * @param value The new value of this setting. 297 * @return This object. 298 */ 299 public SerializedHeader skipIfEmpty(boolean value) { 300 skipIfEmpty = value; 301 return this; 302 } 303}