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