001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.http.annotation;
014
015import static java.lang.annotation.ElementType.*;
016import static java.lang.annotation.RetentionPolicy.*;
017import static org.apache.juneau.common.internal.StringUtils.*;
018import static org.apache.juneau.internal.ArrayUtils.*;
019
020import java.lang.annotation.*;
021import java.lang.reflect.*;
022import org.apache.juneau.*;
023import org.apache.juneau.annotation.*;
024import org.apache.juneau.httppart.*;
025import org.apache.juneau.reflect.*;
026import org.apache.juneau.svl.*;
027
028/**
029 * Utility classes and methods for the {@link Query @Query} annotation.
030 *
031 * <h5 class='section'>See Also:</h5><ul>
032 * </ul>
033 */
034public class QueryAnnotation {
035
036   //-----------------------------------------------------------------------------------------------------------------
037   // Static
038   //-----------------------------------------------------------------------------------------------------------------
039
040   /** Default value */
041   public static final Query DEFAULT = create().build();
042
043   /**
044    * Instantiates a new builder for this class.
045    *
046    * @return A new builder object.
047    */
048   public static Builder create() {
049      return new Builder();
050   }
051
052   /**
053    * Instantiates a new builder for this class.
054    *
055    * @param on The targets this annotation applies to.
056    * @return A new builder object.
057    */
058   public static Builder create(Class<?>...on) {
059      return create().on(on);
060   }
061
062   /**
063    * Instantiates a new builder for this class.
064    *
065    * @param on The targets this annotation applies to.
066    * @return A new builder object.
067    */
068   public static Builder create(String...on) {
069      return create().on(on);
070   }
071
072   /**
073    * Returns <jk>true</jk> if the specified annotation contains all default values.
074    *
075    * @param a The annotation to check.
076    * @return <jk>true</jk> if the specified annotation contains all default values.
077    */
078   public static boolean empty(Query a) {
079      return a == null || DEFAULT.equals(a);
080   }
081
082   /**
083    * Finds the name from the specified list of annotations.
084    *
085    * @param pi The parameter.
086    * @return The last matching name, or {@link Value#empty()} if not found.
087    */
088   public static Value<String> findName(ParamInfo pi) {
089      Value<String> n = Value.empty();
090      pi.forEachAnnotation(Query.class, x -> isNotEmpty(x.value()), x -> n.set(x.value()));
091      pi.forEachAnnotation(Query.class, x -> isNotEmpty(x.name()), x -> n.set(x.name()));
092      return n;
093   }
094
095   /**
096    * Finds the default value from the specified list of annotations.
097    *
098    * @param pi The parameter.
099    * @return The last matching default value, or {@link Value#empty()} if not found.
100    */
101   public static Value<String> findDef(ParamInfo pi) {
102      Value<String> n = Value.empty();
103      pi.forEachAnnotation(Query.class, x -> isNotEmpty(x.def()), x -> n.set(x.def()));
104      return n;
105   }
106
107   //-----------------------------------------------------------------------------------------------------------------
108   // Builder
109   //-----------------------------------------------------------------------------------------------------------------
110
111   /**
112    * Builder class.
113    *
114    * <h5 class='section'>See Also:</h5><ul>
115    *    <li class='jm'>{@link org.apache.juneau.BeanContext.Builder#annotations(Annotation...)}
116    * </ul>
117    */
118   public static class Builder extends TargetedAnnotationTMFBuilder {
119
120      Class<? extends HttpPartParser> parser = HttpPartParser.Void.class;
121      Class<? extends HttpPartSerializer> serializer = HttpPartSerializer.Void.class;
122      Schema schema = SchemaAnnotation.DEFAULT;
123      String name="", value="", def="";
124
125      /**
126       * Constructor.
127       */
128      protected Builder() {
129         super(Query.class);
130      }
131
132      /**
133       * Instantiates a new {@link Query @Query} object initialized with this builder.
134       *
135       * @return A new {@link Query @Query} object.
136       */
137      public Query build() {
138         return new Impl(this);
139      }
140
141      /**
142       * Sets the {@link Query#def} property on this annotation.
143       *
144       * @param value The new value for this property.
145       * @return This object.
146       */
147      public Builder def(String value) {
148         this.def = value;
149         return this;
150      }
151
152      /**
153       * Sets the {@link Query#name} property on this annotation.
154       *
155       * @param value The new value for this property.
156       * @return This object.
157       */
158      public Builder name(String value) {
159         this.name = value;
160         return this;
161      }
162
163      /**
164       * Sets the {@link Query#parser} property on this annotation.
165       *
166       * @param value The new value for this property.
167       * @return This object.
168       */
169      public Builder parser(Class<? extends HttpPartParser> value) {
170         this.parser = value;
171         return this;
172      }
173
174      /**
175       * Sets the {@link Query#schema} property on this annotation.
176       *
177       * @param value The new value for this property.
178       * @return This object.
179       */
180      public Builder schema(Schema value) {
181         this.schema = value;
182         return this;
183      }
184
185      /**
186       * Sets the {@link Query#serializer} property on this annotation.
187       *
188       * @param value The new value for this property.
189       * @return This object.
190       */
191      public Builder serializer(Class<? extends HttpPartSerializer> value) {
192         this.serializer = value;
193         return this;
194      }
195
196      /**
197       * Sets the {@link Query#value} property on this annotation.
198       *
199       * @param value The new value for this property.
200       * @return This object.
201       */
202      public Builder value(String value) {
203         this.value = value;
204         return this;
205      }
206
207      // <FluentSetters>
208
209      @Override /* GENERATED - TargetedAnnotationBuilder */
210      public Builder on(String...values) {
211         super.on(values);
212         return this;
213      }
214
215      @Override /* GENERATED - TargetedAnnotationTBuilder */
216      public Builder on(java.lang.Class<?>...value) {
217         super.on(value);
218         return this;
219      }
220
221      @Override /* GENERATED - TargetedAnnotationTBuilder */
222      public Builder onClass(java.lang.Class<?>...value) {
223         super.onClass(value);
224         return this;
225      }
226
227      @Override /* GENERATED - TargetedAnnotationTMFBuilder */
228      public Builder on(Field...value) {
229         super.on(value);
230         return this;
231      }
232
233      @Override /* GENERATED - TargetedAnnotationTMFBuilder */
234      public Builder on(Method...value) {
235         super.on(value);
236         return this;
237      }
238
239      // </FluentSetters>
240   }
241
242   //-----------------------------------------------------------------------------------------------------------------
243   // Implementation
244   //-----------------------------------------------------------------------------------------------------------------
245
246   private static class Impl extends TargetedAnnotationTImpl implements Query {
247
248      private final Class<? extends HttpPartParser> parser;
249      private final Class<? extends HttpPartSerializer> serializer;
250      private final String name, value, def;
251      private final Schema schema;
252
253      Impl(Builder b) {
254         super(b);
255         this.name = b.name;
256         this.parser = b.parser;
257         this.schema = b.schema;
258         this.serializer = b.serializer;
259         this.value = b.value;
260         this.def = b.def;
261         postConstruct();
262      }
263
264      @Override /* Query */
265      public String name() {
266         return name;
267      }
268
269      @Override /* Query */
270      public Class<? extends HttpPartParser> parser() {
271         return parser;
272      }
273
274      @Override /* Query */
275      public Schema schema() {
276         return schema;
277      }
278
279      @Override /* Query */
280      public Class<? extends HttpPartSerializer> serializer() {
281         return serializer;
282      }
283
284      @Override /* Query */
285      public String value() {
286         return value;
287      }
288
289      @Override /* Query */
290      public String def() {
291         return def;
292      }
293   }
294
295   //-----------------------------------------------------------------------------------------------------------------
296   // Appliers
297   //-----------------------------------------------------------------------------------------------------------------
298
299   /**
300    * Applies targeted {@link Query} annotations to a {@link org.apache.juneau.BeanContext.Builder}.
301    */
302   public static class Applier extends AnnotationApplier<Query,BeanContext.Builder> {
303
304      /**
305       * Constructor.
306       *
307       * @param vr The resolver for resolving values in annotations.
308       */
309      public Applier(VarResolverSession vr) {
310         super(Query.class, BeanContext.Builder.class, vr);
311      }
312
313      @Override
314      public void apply(AnnotationInfo<Query> ai, BeanContext.Builder b) {
315         Query a = ai.inner();
316         if (isEmptyArray(a.on(), a.onClass()))
317            return;
318         b.annotations(a);
319      }
320   }
321
322   //-----------------------------------------------------------------------------------------------------------------
323   // Other
324   //-----------------------------------------------------------------------------------------------------------------
325
326   /**
327    * A collection of {@link Query @Query annotations}.
328    */
329   @Documented
330   @Target({METHOD,TYPE})
331   @Retention(RUNTIME)
332   @Inherited
333   public static @interface Array {
334
335      /**
336       * The child annotations.
337       *
338       * @return The annotation value.
339       */
340      Query[] value();
341   }
342}