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.annotation; 018 019import static java.lang.annotation.ElementType.*; 020import static java.lang.annotation.RetentionPolicy.*; 021import static org.apache.juneau.commons.utils.CollectionUtils.*; 022import static org.apache.juneau.commons.utils.StringUtils.*; 023import static org.apache.juneau.commons.utils.Utils.*; 024 025import java.lang.annotation.*; 026import java.lang.reflect.*; 027import java.util.*; 028 029import org.apache.juneau.*; 030import org.apache.juneau.annotation.*; 031import org.apache.juneau.httppart.*; 032import org.apache.juneau.commons.annotation.*; 033import org.apache.juneau.commons.reflect.*; 034import org.apache.juneau.svl.*; 035 036/** 037 * Utility classes and methods for the {@link FormData @FormData} annotation. 038 * 039 */ 040public class FormDataAnnotation { 041 042 private static final AnnotationProvider AP = AnnotationProvider.INSTANCE; 043 044 /** 045 * Applies targeted {@link FormData} annotations to a {@link org.apache.juneau.BeanContext.Builder}. 046 */ 047 public static class Applier extends AnnotationApplier<FormData,BeanContext.Builder> { 048 049 /** 050 * Constructor. 051 * 052 * @param vr The resolver for resolving values in annotations. 053 */ 054 public Applier(VarResolverSession vr) { 055 super(FormData.class, BeanContext.Builder.class, vr); 056 } 057 058 @Override 059 public void apply(AnnotationInfo<FormData> ai, BeanContext.Builder b) { 060 var a = ai.inner(); 061 if (isEmptyArray(a.on()) && isEmptyArray(a.onClass())) 062 return; 063 b.annotations(a); 064 } 065 } 066 067 /** 068 * A collection of {@link FormData @FormData annotations}. 069 */ 070 @Documented 071 @Target({ METHOD, TYPE }) 072 @Retention(RUNTIME) 073 @Inherited 074 public static @interface Array { 075 076 /** 077 * The child annotations. 078 * 079 * @return The annotation value. 080 */ 081 FormData[] value(); 082 } 083 084 /** 085 * Builder class. 086 * 087 * <h5 class='section'>See Also:</h5><ul> 088 * <li class='jm'>{@link org.apache.juneau.BeanContext.Builder#annotations(Annotation...)} 089 * </ul> 090 */ 091 public static class Builder extends AppliedAnnotationObject.BuilderTMF { 092 093 private String[] description = {}; 094 private Class<? extends HttpPartParser> parser = HttpPartParser.Void.class; 095 private Class<? extends HttpPartSerializer> serializer = HttpPartSerializer.Void.class; 096 private Schema schema = SchemaAnnotation.DEFAULT; 097 private String def = "", name = "", value = ""; 098 099 /** 100 * Constructor. 101 */ 102 protected Builder() { 103 super(FormData.class); 104 } 105 106 /** 107 * Instantiates a new {@link FormData @FormData} object initialized with this builder. 108 * 109 * @return A new {@link FormData @FormData} object. 110 */ 111 public FormData build() { 112 return new Object(this); 113 } 114 115 /** 116 * Sets the description property on this annotation. 117 * 118 * @param value The new value for this property. 119 * @return This object. 120 */ 121 public Builder description(String...value) { 122 description = value; 123 return this; 124 } 125 126 /** 127 * Sets the {@link FormData#def} property on this annotation. 128 * 129 * @param value The new value for this property. 130 * @return This object. 131 */ 132 public Builder def(String value) { 133 def = value; 134 return this; 135 } 136 137 /** 138 * Sets the {@link FormData#name} property on this annotation. 139 * 140 * @param value The new value for this property. 141 * @return This object. 142 */ 143 public Builder name(String value) { 144 name = value; 145 return this; 146 } 147 148 /** 149 * Sets the {@link FormData#parser} property on this annotation. 150 * 151 * @param value The new value for this property. 152 * @return This object. 153 */ 154 public Builder parser(Class<? extends HttpPartParser> value) { 155 parser = value; 156 return this; 157 } 158 159 /** 160 * Sets the {@link FormData#schema} property on this annotation. 161 * 162 * @param value The new value for this property. 163 * @return This object. 164 */ 165 public Builder schema(Schema value) { 166 schema = value; 167 return this; 168 } 169 170 /** 171 * Sets the {@link FormData#serializer} property on this annotation. 172 * 173 * @param value The new value for this property. 174 * @return This object. 175 */ 176 public Builder serializer(Class<? extends HttpPartSerializer> value) { 177 serializer = value; 178 return this; 179 } 180 181 /** 182 * Sets the {@link FormData#value} property on this annotation. 183 * 184 * @param value The new value for this property. 185 * @return This object. 186 */ 187 public Builder value(String value) { 188 this.value = value; 189 return this; 190 } 191 192 @Override /* Overridden from AppliedAnnotationObject.Builder */ 193 public Builder on(String...value) { 194 super.on(value); 195 return this; 196 } 197 198 @Override /* Overridden from AppliedAnnotationObject.BuilderT */ 199 public Builder on(Class<?>...value) { 200 super.on(value); 201 return this; 202 } 203 204 @Override /* Overridden from AppliedOnClassAnnotationObject.Builder */ 205 public Builder onClass(Class<?>...value) { 206 super.onClass(value); 207 return this; 208 } 209 210 @Override /* Overridden from AppliedAnnotationObject.BuilderM */ 211 public Builder on(Method...value) { 212 super.on(value); 213 return this; 214 } 215 216 @Override /* Overridden from AppliedAnnotationObject.BuilderMF */ 217 public Builder on(Field...value) { 218 super.on(value); 219 return this; 220 } 221 222 @Override /* Overridden from AppliedAnnotationObject.BuilderT */ 223 public Builder on(ClassInfo...value) { 224 super.on(value); 225 return this; 226 } 227 228 @Override /* Overridden from AppliedAnnotationObject.BuilderT */ 229 public Builder onClass(ClassInfo...value) { 230 super.onClass(value); 231 return this; 232 } 233 234 @Override /* Overridden from AppliedAnnotationObject.BuilderTMF */ 235 public Builder on(FieldInfo...value) { 236 super.on(value); 237 return this; 238 } 239 240 @Override /* Overridden from AppliedAnnotationObject.BuilderTMF */ 241 public Builder on(MethodInfo...value) { 242 super.on(value); 243 return this; 244 } 245 246 } 247 248 private static class Object extends AppliedOnClassAnnotationObject implements FormData { 249 250 private final String[] description; 251 private final Class<? extends HttpPartParser> parser; 252 private final Class<? extends HttpPartSerializer> serializer; 253 private final String name, value, def; 254 private final Schema schema; 255 256 Object(FormDataAnnotation.Builder b) { 257 super(b); 258 description = copyOf(b.description); 259 def = b.def; 260 name = b.name; 261 parser = b.parser; 262 schema = b.schema; 263 serializer = b.serializer; 264 value = b.value; 265 } 266 267 @Override /* Overridden from FormData */ 268 public String def() { 269 return def; 270 } 271 272 @Override /* Overridden from FormData */ 273 public String name() { 274 return name; 275 } 276 277 @Override /* Overridden from FormData */ 278 public Class<? extends HttpPartParser> parser() { 279 return parser; 280 } 281 282 @Override /* Overridden from FormData */ 283 public Schema schema() { 284 return schema; 285 } 286 287 @Override /* Overridden from FormData */ 288 public Class<? extends HttpPartSerializer> serializer() { 289 return serializer; 290 } 291 292 @Override 293 public String value() { 294 return value; 295 } 296 297 @Override /* Overridden from annotation */ 298 public String[] description() { 299 return description; 300 } 301 } 302 303 /** Default value */ 304 public static final FormData DEFAULT = create().build(); 305 306 /** 307 * Instantiates a new builder for this class. 308 * 309 * @return A new builder object. 310 */ 311 public static Builder create() { 312 return new Builder(); 313 } 314 315 /** 316 * Instantiates a new builder for this class. 317 * 318 * @param on The targets this annotation applies to. 319 * @return A new builder object. 320 */ 321 public static Builder create(Class<?>...on) { 322 return create().on(on); 323 } 324 325 /** 326 * Instantiates a new builder for this class. 327 * 328 * @param on The targets this annotation applies to. 329 * @return A new builder object. 330 */ 331 public static Builder create(String...on) { 332 return create().on(on); 333 } 334 335 /** 336 * Returns <jk>true</jk> if the specified annotation contains all default values. 337 * 338 * @param a The annotation to check. 339 * @return <jk>true</jk> if the specified annotation contains all default values. 340 */ 341 public static boolean empty(FormData a) { 342 return a == null || DEFAULT.equals(a); 343 } 344 345 /** 346 * Finds the default value from the specified list of annotations. 347 * 348 * @param pi The parameter. 349 * @return The last matching default value, or empty if not found. 350 */ 351 public static Optional<String> findDef(ParameterInfo pi) { 352 // @formatter:off 353 return AP.find(FormData.class, pi) 354 .stream() 355 .map(AnnotationInfo::inner) 356 .filter(x -> ne(x.def())) 357 .findFirst() 358 .map(x -> x.def()); 359 // @formatter:on 360 } 361 362 /** 363 * Finds the name from the specified lists of annotations. 364 * 365 * <p> 366 * The last matching name found is returned. 367 * 368 * @param pi The parameter. 369 * @return The last matching name, or empty if not found. 370 */ 371 public static Optional<String> findName(ParameterInfo pi) { 372 return AP.find(FormData.class, pi).stream().map(AnnotationInfo::inner).filter(x -> isAnyNotBlank(x.value(), x.name())).findFirst().map(x -> firstNonBlank(x.name(), x.value())); 373 } 374}