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.annotation;
018
019import static java.lang.annotation.ElementType.*;
020import static java.lang.annotation.RetentionPolicy.*;
021import static org.apache.juneau.internal.ArrayUtils.*;
022
023import java.lang.annotation.*;
024
025import org.apache.juneau.*;
026import org.apache.juneau.reflect.*;
027import org.apache.juneau.svl.*;
028import org.apache.juneau.swap.*;
029
030/**
031 * Utility classes and methods for the {@link Bean @Bean} annotation.
032 *
033 * <h5 class='section'>See Also:</h5><ul>
034 * </ul>
035 */
036public class BeanAnnotation {
037
038   //-----------------------------------------------------------------------------------------------------------------
039   // Static
040   //-----------------------------------------------------------------------------------------------------------------
041
042   /** Default value */
043   public static final Bean DEFAULT = create().build();
044
045   /**
046    * Instantiates a new builder for this class.
047    *
048    * @return A new builder object.
049    */
050   public static Builder create() {
051      return new Builder();
052   }
053
054   /**
055    * Instantiates a new builder for this class.
056    *
057    * @param on The targets this annotation applies to.
058    * @return A new builder object.
059    */
060   public static Builder create(Class<?>...on) {
061      return create().on(on);
062   }
063
064   /**
065    * Instantiates a new builder for this class.
066    *
067    * @param on The targets this annotation applies to.
068    * @return A new builder object.
069    */
070   public static Builder create(String...on) {
071      return create().on(on);
072   }
073
074   /**
075    * Creates a copy of the specified annotation.
076    *
077    * @param a The annotation to copy.
078    * @param r The var resolver for resolving any variables.
079    * @return A copy of the specified annotation.
080    */
081   public static Bean copy(Bean a, VarResolverSession r) {
082      return
083         create()
084         .dictionary(a.dictionary())
085         .example(r.resolve(a.example()))
086         .excludeProperties(r.resolve(a.excludeProperties()))
087         .findFluentSetters(a.findFluentSetters())
088         .implClass(a.implClass())
089         .interceptor(a.interceptor())
090         .interfaceClass(a.interfaceClass())
091         .on(r.resolve(a.on()))
092         .onClass(a.onClass())
093         .p(r.resolve(a.p()))
094         .properties(r.resolve(a.properties()))
095         .propertyNamer(a.propertyNamer())
096         .readOnlyProperties(r.resolve(a.readOnlyProperties()))
097         .ro(r.resolve(a.ro()))
098         .sort(a.sort())
099         .stopClass(a.stopClass())
100         .typeName(r.resolve(a.typeName()))
101         .typePropertyName(r.resolve(a.typePropertyName()))
102         .wo(r.resolve(a.wo()))
103         .writeOnlyProperties(r.resolve(a.writeOnlyProperties()))
104         .xp(r.resolve(a.xp()))
105         .build();
106   }
107
108   //-----------------------------------------------------------------------------------------------------------------
109   // Builder
110   //-----------------------------------------------------------------------------------------------------------------
111
112   /**
113    * Builder class.
114    *
115    * <h5 class='section'>See Also:</h5><ul>
116    *    <li class='jm'>{@link org.apache.juneau.BeanContext.Builder#annotations(Annotation...)}
117    * </ul>
118    */
119   public static class Builder extends TargetedAnnotationTBuilder<Builder> {
120
121      Class<?>[] dictionary = new Class[0];
122      Class<?> implClass=void.class, interfaceClass=void.class, stopClass=void.class;
123      Class<? extends BeanInterceptor<?>> interceptor=BeanInterceptor.Void.class;
124      Class<? extends PropertyNamer> propertyNamer=BasicPropertyNamer.class;
125      String example="", excludeProperties="", p="", properties="", readOnlyProperties="", ro="", typeName="", typePropertyName="", wo="", writeOnlyProperties="", xp="";
126      boolean findFluentSetters, sort;
127
128      /**
129       * Constructor.
130       */
131      protected Builder() {
132         super(Bean.class);
133      }
134
135      /**
136       * Instantiates a new {@link Bean @Bean} object initialized with this builder.
137       *
138       * @return A new {@link Bean @Bean} object.
139       */
140      public Bean build() {
141         return new Impl(this);
142      }
143
144      /**
145       * Sets the {@link Bean#dictionary()} property on this annotation.
146       *
147       * @param value The new value for this property.
148       * @return This object.
149       */
150      public Builder dictionary(Class<?>...value) {
151         this.dictionary = value;
152         return this;
153      }
154
155      /**
156       * Sets the {@link Bean#example()} property on this annotation.
157       *
158       * @param value The new value for this property.
159       * @return This object.
160       */
161      public Builder example(String value) {
162         this.example = value;
163         return this;
164      }
165
166      /**
167       * Sets the {@link Bean#excludeProperties()} property on this annotation.
168       *
169       * @param value The new value for this property.
170       * @return This object.
171       */
172      public Builder excludeProperties(String value) {
173         this.excludeProperties = value;
174         return this;
175      }
176
177      /**
178       * Sets the {@link Bean#findFluentSetters()} property on this annotation.
179       *
180       * @param value The new value for this property.
181       * @return This object.
182       */
183      public Builder findFluentSetters(boolean value) {
184         this.findFluentSetters = value;
185         return this;
186      }
187
188      /**
189       * Sets the {@link Bean#implClass()} property on this annotation.
190       *
191       * @param value The new value for this property.
192       * @return This object.
193       */
194      public Builder implClass(Class<?> value) {
195         this.implClass = value;
196         return this;
197      }
198
199      /**
200       * Sets the {@link Bean#interceptor()} property on this annotation.
201       *
202       * @param value The new value for this property.
203       * @return This object.
204       */
205      public Builder interceptor(Class<? extends BeanInterceptor<?>> value) {
206         this.interceptor = value;
207         return this;
208      }
209
210      /**
211       * Sets the {@link Bean#interfaceClass()} property on this annotation.
212       *
213       * @param value The new value for this property.
214       * @return This object.
215       */
216      public Builder interfaceClass(Class<?> value) {
217         this.interfaceClass = value;
218         return this;
219      }
220
221      /**
222       * Sets the {@link Bean#properties()} property on this annotation.
223       *
224       * @param value The new value for this property.
225       * @return This object.
226       */
227      public Builder properties(String value) {
228         this.properties = value;
229         return this;
230      }
231
232      /**
233       * Sets the {@link Bean#p()} property on this annotation.
234       *
235       * @param value The new value for this property.
236       * @return This object.
237       */
238      public Builder p(String value) {
239         this.p = value;
240         return this;
241      }
242
243      /**
244       * Sets the {@link Bean#propertyNamer()} property on this annotation.
245       *
246       * @param value The new value for this property.
247       * @return This object.
248       */
249      public Builder propertyNamer(Class<? extends PropertyNamer> value) {
250         this.propertyNamer = value;
251         return this;
252      }
253
254      /**
255       * Sets the {@link Bean#readOnlyProperties()} property on this annotation.
256       *
257       * @param value The new value for this property.
258       * @return This object.
259       */
260      public Builder readOnlyProperties(String value) {
261         this.readOnlyProperties = value;
262         return this;
263      }
264
265      /**
266       * Sets the {@link Bean#ro()} property on this annotation.
267       *
268       * @param value The new value for this property.
269       * @return This object.
270       */
271      public Builder ro(String value) {
272         this.ro = value;
273         return this;
274      }
275
276      /**
277       * Sets the {@link Bean#sort()} property on this annotation.
278       *
279       * @param value The new value for this property.
280       * @return This object.
281       */
282      public Builder sort(boolean value) {
283         this.sort = value;
284         return this;
285      }
286
287      /**
288       * Sets the {@link Bean#stopClass()} property on this annotation.
289       *
290       * @param value The new value for this property.
291       * @return This object.
292       */
293      public Builder stopClass(Class<?> value) {
294         this.stopClass = value;
295         return this;
296      }
297
298      /**
299       * Sets the {@link Bean#typeName()} property on this annotation.
300       *
301       * @param value The new value for this property.
302       * @return This object.
303       */
304      public Builder typeName(String value) {
305         this.typeName = value;
306         return this;
307      }
308
309      /**
310       * Sets the {@link Bean#typePropertyName()} property on this annotation.
311       *
312       * @param value The new value for this property.
313       * @return This object.
314       */
315      public Builder typePropertyName(String value) {
316         this.typePropertyName = value;
317         return this;
318      }
319
320      /**
321       * Sets the{@link Bean#wo()} property on this annotation.
322       *
323       * @param value The new value for this property.
324       * @return This object.
325       */
326      public Builder wo(String value) {
327         this.wo = value;
328         return this;
329      }
330
331      /**
332       * Sets the{@link Bean#writeOnlyProperties()} property on this annotation.
333       *
334       * @param value The new value for this property.
335       * @return This object.
336       */
337      public Builder writeOnlyProperties(String value) {
338         this.writeOnlyProperties = value;
339         return this;
340      }
341
342      /**
343       * Sets the {@link Bean#xp()} property on this annotation.
344       *
345       * @param value The new value for this property.
346       * @return This object.
347       */
348      public Builder xp(String value) {
349         this.xp = value;
350         return this;
351      }
352
353   }
354
355   //-----------------------------------------------------------------------------------------------------------------
356   // Implementation
357   //-----------------------------------------------------------------------------------------------------------------
358
359   private static class Impl extends TargetedAnnotationTImpl implements Bean {
360
361      private final boolean findFluentSetters, sort;
362      private final Class<? extends BeanInterceptor<?>> interceptor;
363      private final Class<? extends PropertyNamer> propertyNamer;
364      private final Class<?> implClass, interfaceClass, stopClass;
365      private final Class<?>[] dictionary;
366      private final String example, excludeProperties, p, properties, readOnlyProperties, ro, typeName, typePropertyName, wo, writeOnlyProperties, xp;
367
368      Impl(Builder b) {
369         super(b);
370         this.dictionary = copyOf(b.dictionary);
371         this.example = b.example;
372         this.excludeProperties = b.excludeProperties;
373         this.findFluentSetters = b.findFluentSetters;
374         this.implClass = b.implClass;
375         this.interceptor = b.interceptor;
376         this.interfaceClass = b.interfaceClass;
377         this.p = b.p;
378         this.properties = b.properties;
379         this.propertyNamer = b.propertyNamer;
380         this.readOnlyProperties = b.readOnlyProperties;
381         this.ro = b.ro;
382         this.sort = b.sort;
383         this.stopClass = b.stopClass;
384         this.typeName = b.typeName;
385         this.typePropertyName = b.typePropertyName;
386         this.wo = b.wo;
387         this.writeOnlyProperties = b.writeOnlyProperties;
388         this.xp = b.xp;
389         postConstruct();
390      }
391
392      @Override /* Bean */
393      public Class<?>[] dictionary() {
394         return dictionary;
395      }
396
397      @Override /* Bean */
398      public String example() {
399         return example;
400      }
401
402      @Override /* Bean */
403      public String excludeProperties() {
404         return excludeProperties;
405      }
406
407      @Override /* Bean */
408      public boolean findFluentSetters() {
409         return findFluentSetters;
410      }
411
412      @Override /* Bean */
413      public Class<?> implClass() {
414         return implClass;
415      }
416
417      @Override /* Bean */
418      public Class<? extends BeanInterceptor<?>> interceptor() {
419         return interceptor;
420      }
421
422      @Override /* Bean */
423      public Class<?> interfaceClass() {
424         return interfaceClass;
425      }
426
427      @Override /* Bean */
428      public String p() {
429         return p;
430      }
431
432      @Override /* Bean */
433      public String properties() {
434         return properties;
435      }
436
437      @Override /* Bean */
438      public Class<? extends PropertyNamer> propertyNamer() {
439         return propertyNamer;
440      }
441
442      @Override /* Bean */
443      public String readOnlyProperties() {
444         return readOnlyProperties;
445      }
446
447      @Override /* Bean */
448      public String ro() {
449         return ro;
450      }
451
452      @Override /* Bean */
453      public boolean sort() {
454         return sort;
455      }
456
457      @Override /* Bean */
458      public Class<?> stopClass() {
459         return stopClass;
460      }
461
462      @Override /* Bean */
463      public String typeName() {
464         return typeName;
465      }
466
467      @Override /* Bean */
468      public String typePropertyName() {
469         return typePropertyName;
470      }
471
472      @Override /* Bean */
473      public String writeOnlyProperties() {
474         return writeOnlyProperties;
475      }
476
477      @Override /* Bean */
478      public String wo() {
479         return wo;
480      }
481
482      @Override /* Bean */
483      public String xp() {
484         return xp;
485      }
486   }
487
488   //-----------------------------------------------------------------------------------------------------------------
489   // Appliers
490   //-----------------------------------------------------------------------------------------------------------------
491
492   /**
493    * Applies targeted {@link Bean} annotations to a {@link org.apache.juneau.BeanContext.Builder}.
494    */
495   public static class Applier extends AnnotationApplier<Bean,BeanContext.Builder> {
496
497      /**
498       * Constructor.
499       *
500       * @param vr The resolver for resolving values in annotations.
501       */
502      public Applier(VarResolverSession vr) {
503         super(Bean.class, BeanContext.Builder.class, vr);
504      }
505
506      @Override
507      public void apply(AnnotationInfo<Bean> ai, BeanContext.Builder b) {
508         Bean a = ai.inner();
509         if (isEmptyArray(a.on(), a.onClass()))
510            return;
511         b.annotations(copy(a, vr()));
512      }
513   }
514
515   //-----------------------------------------------------------------------------------------------------------------
516   // Other
517   //-----------------------------------------------------------------------------------------------------------------
518
519   /**
520    * A collection of {@link Bean @Bean annotations}.
521    */
522   @Documented
523   @Target({METHOD,TYPE})
524   @Retention(RUNTIME)
525   @Inherited
526   public static @interface Array {
527
528      /**
529       * The child annotations.
530       *
531       * @return The annotation value.
532       */
533      Bean[] value();
534   }
535}