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.common.utils.Utils.*;
022import static org.apache.juneau.internal.ArrayUtils.*;
023
024import java.lang.annotation.*;
025
026import org.apache.juneau.*;
027import org.apache.juneau.annotation.*;
028import org.apache.juneau.httppart.*;
029import org.apache.juneau.reflect.*;
030import org.apache.juneau.svl.*;
031
032/**
033 * Utility classes and methods for the {@link Query @Query} annotation.
034 *
035 * <h5 class='section'>See Also:</h5><ul>
036 * </ul>
037 */
038public class QueryAnnotation {
039
040   //-----------------------------------------------------------------------------------------------------------------
041   // Static
042   //-----------------------------------------------------------------------------------------------------------------
043
044   /** Default value */
045   public static final Query DEFAULT = create().build();
046
047   /**
048    * Instantiates a new builder for this class.
049    *
050    * @return A new builder object.
051    */
052   public static Builder create() {
053      return new Builder();
054   }
055
056   /**
057    * Instantiates a new builder for this class.
058    *
059    * @param on The targets this annotation applies to.
060    * @return A new builder object.
061    */
062   public static Builder create(Class<?>...on) {
063      return create().on(on);
064   }
065
066   /**
067    * Instantiates a new builder for this class.
068    *
069    * @param on The targets this annotation applies to.
070    * @return A new builder object.
071    */
072   public static Builder create(String...on) {
073      return create().on(on);
074   }
075
076   /**
077    * Returns <jk>true</jk> if the specified annotation contains all default values.
078    *
079    * @param a The annotation to check.
080    * @return <jk>true</jk> if the specified annotation contains all default values.
081    */
082   public static boolean empty(Query a) {
083      return a == null || DEFAULT.equals(a);
084   }
085
086   /**
087    * Finds the name from the specified list of annotations.
088    *
089    * @param pi The parameter.
090    * @return The last matching name, or {@link Value#empty()} if not found.
091    */
092   public static Value<String> findName(ParamInfo pi) {
093      Value<String> n = Value.empty();
094      pi.forEachAnnotation(Query.class, x -> isNotEmpty(x.value()), x -> n.set(x.value()));
095      pi.forEachAnnotation(Query.class, x -> isNotEmpty(x.name()), x -> n.set(x.name()));
096      return n;
097   }
098
099   /**
100    * Finds the default value from the specified list of annotations.
101    *
102    * @param pi The parameter.
103    * @return The last matching default value, or {@link Value#empty()} if not found.
104    */
105   public static Value<String> findDef(ParamInfo pi) {
106      Value<String> n = Value.empty();
107      pi.forEachAnnotation(Query.class, x -> isNotEmpty(x.def()), x -> n.set(x.def()));
108      return n;
109   }
110
111   //-----------------------------------------------------------------------------------------------------------------
112   // Builder
113   //-----------------------------------------------------------------------------------------------------------------
114
115   /**
116    * Builder class.
117    *
118    * <h5 class='section'>See Also:</h5><ul>
119    *    <li class='jm'>{@link org.apache.juneau.BeanContext.Builder#annotations(Annotation...)}
120    * </ul>
121    */
122   public static class Builder extends TargetedAnnotationTMFBuilder<Builder> {
123
124      Class<? extends HttpPartParser> parser = HttpPartParser.Void.class;
125      Class<? extends HttpPartSerializer> serializer = HttpPartSerializer.Void.class;
126      Schema schema = SchemaAnnotation.DEFAULT;
127      String name="", value="", def="";
128
129      /**
130       * Constructor.
131       */
132      protected Builder() {
133         super(Query.class);
134      }
135
136      /**
137       * Instantiates a new {@link Query @Query} object initialized with this builder.
138       *
139       * @return A new {@link Query @Query} object.
140       */
141      public Query build() {
142         return new Impl(this);
143      }
144
145      /**
146       * Sets the {@link Query#def} property on this annotation.
147       *
148       * @param value The new value for this property.
149       * @return This object.
150       */
151      public Builder def(String value) {
152         this.def = value;
153         return this;
154      }
155
156      /**
157       * Sets the {@link Query#name} property on this annotation.
158       *
159       * @param value The new value for this property.
160       * @return This object.
161       */
162      public Builder name(String value) {
163         this.name = value;
164         return this;
165      }
166
167      /**
168       * Sets the {@link Query#parser} property on this annotation.
169       *
170       * @param value The new value for this property.
171       * @return This object.
172       */
173      public Builder parser(Class<? extends HttpPartParser> value) {
174         this.parser = value;
175         return this;
176      }
177
178      /**
179       * Sets the {@link Query#schema} property on this annotation.
180       *
181       * @param value The new value for this property.
182       * @return This object.
183       */
184      public Builder schema(Schema value) {
185         this.schema = value;
186         return this;
187      }
188
189      /**
190       * Sets the {@link Query#serializer} property on this annotation.
191       *
192       * @param value The new value for this property.
193       * @return This object.
194       */
195      public Builder serializer(Class<? extends HttpPartSerializer> value) {
196         this.serializer = value;
197         return this;
198      }
199
200      /**
201       * Sets the {@link Query#value} property on this annotation.
202       *
203       * @param value The new value for this property.
204       * @return This object.
205       */
206      public Builder value(String value) {
207         this.value = value;
208         return this;
209      }
210
211   }
212
213   //-----------------------------------------------------------------------------------------------------------------
214   // Implementation
215   //-----------------------------------------------------------------------------------------------------------------
216
217   private static class Impl extends TargetedAnnotationTImpl implements Query {
218
219      private final Class<? extends HttpPartParser> parser;
220      private final Class<? extends HttpPartSerializer> serializer;
221      private final String name, value, def;
222      private final Schema schema;
223
224      Impl(Builder b) {
225         super(b);
226         this.name = b.name;
227         this.parser = b.parser;
228         this.schema = b.schema;
229         this.serializer = b.serializer;
230         this.value = b.value;
231         this.def = b.def;
232         postConstruct();
233      }
234
235      @Override /* Query */
236      public String name() {
237         return name;
238      }
239
240      @Override /* Query */
241      public Class<? extends HttpPartParser> parser() {
242         return parser;
243      }
244
245      @Override /* Query */
246      public Schema schema() {
247         return schema;
248      }
249
250      @Override /* Query */
251      public Class<? extends HttpPartSerializer> serializer() {
252         return serializer;
253      }
254
255      @Override /* Query */
256      public String value() {
257         return value;
258      }
259
260      @Override /* Query */
261      public String def() {
262         return def;
263      }
264   }
265
266   //-----------------------------------------------------------------------------------------------------------------
267   // Appliers
268   //-----------------------------------------------------------------------------------------------------------------
269
270   /**
271    * Applies targeted {@link Query} annotations to a {@link org.apache.juneau.BeanContext.Builder}.
272    */
273   public static class Applier extends AnnotationApplier<Query,BeanContext.Builder> {
274
275      /**
276       * Constructor.
277       *
278       * @param vr The resolver for resolving values in annotations.
279       */
280      public Applier(VarResolverSession vr) {
281         super(Query.class, BeanContext.Builder.class, vr);
282      }
283
284      @Override
285      public void apply(AnnotationInfo<Query> ai, BeanContext.Builder b) {
286         Query a = ai.inner();
287         if (isEmptyArray(a.on(), a.onClass()))
288            return;
289         b.annotations(a);
290      }
291   }
292
293   //-----------------------------------------------------------------------------------------------------------------
294   // Other
295   //-----------------------------------------------------------------------------------------------------------------
296
297   /**
298    * A collection of {@link Query @Query annotations}.
299    */
300   @Documented
301   @Target({METHOD,TYPE})
302   @Retention(RUNTIME)
303   @Inherited
304   public static @interface Array {
305
306      /**
307       * The child annotations.
308       *
309       * @return The annotation value.
310       */
311      Query[] value();
312   }
313}