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 Query @Query} annotation.
038 *
039 */
040public class QueryAnnotation {
041
042   private static final AnnotationProvider AP = AnnotationProvider.INSTANCE;
043
044   /**
045    * Applies targeted {@link Query} annotations to a {@link org.apache.juneau.BeanContext.Builder}.
046    */
047   public static class Applier extends AnnotationApplier<Query,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(Query.class, BeanContext.Builder.class, vr);
056      }
057
058      @Override
059      public void apply(AnnotationInfo<Query> 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 Query @Query 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      Query[] 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 name = "", value = "", def = "";
098
099      /**
100       * Constructor.
101       */
102      protected Builder() {
103         super(Query.class);
104      }
105
106      /**
107       * Instantiates a new {@link Query @Query} object initialized with this builder.
108       *
109       * @return A new {@link Query @Query} object.
110       */
111      public Query 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 Query#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 Query#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 Query#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 Query#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 Query#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 Query#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 Query {
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(QueryAnnotation.Builder b) {
257         super(b);
258         description = copyOf(b.description);
259         name = b.name;
260         parser = b.parser;
261         schema = b.schema;
262         serializer = b.serializer;
263         value = b.value;
264         def = b.def;
265      }
266
267      @Override /* Overridden from Query */
268      public String def() {
269         return def;
270      }
271
272      @Override /* Overridden from Query */
273      public String name() {
274         return name;
275      }
276
277      @Override /* Overridden from Query */
278      public Class<? extends HttpPartParser> parser() {
279         return parser;
280      }
281
282      @Override /* Overridden from Query */
283      public Schema schema() {
284         return schema;
285      }
286
287      @Override /* Overridden from Query */
288      public Class<? extends HttpPartSerializer> serializer() {
289         return serializer;
290      }
291
292      @Override /* Overridden from Query */
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 Query 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(Query 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(Query.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 list of annotations.
364    *
365    * @param pi The parameter.
366    * @return The last matching name, or empty if not found.
367    */
368   public static Optional<String> findName(ParameterInfo pi) {
369      // @formatter:off
370      return AP.find(Query.class, pi)
371         .stream()
372         .map(AnnotationInfo::inner)
373         .filter(x -> isAnyNotBlank(x.value(), x.name()))
374         .findFirst()
375         .map(x -> firstNonBlank(x.name(), x.value()));
376      // @formatter:on
377   }
378}