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.marshall;
018
019import static org.apache.juneau.commons.utils.CollectionUtils.*;
020
021import java.lang.annotation.*;
022import java.lang.reflect.*;
023
024import org.apache.juneau.commons.*;
025import org.apache.juneau.commons.bean.*;
026import org.apache.juneau.commons.reflect.*;
027import org.apache.juneau.commons.svl.*;
028
029/**
030 * Utility classes and methods for the {@link BeanCtorApply @BeanCtorApply} annotation.
031 *
032 */
033public class BeanCtorApplyAnnotation {
034
035   /**
036    * Prevents instantiation.
037    */
038   private BeanCtorApplyAnnotation() {}
039
040   /**
041    * Applies targeted {@link BeanCtorApply} annotations to a {@link Context.Builder}.
042    *
043    * <p>
044    * Passes the {@link BeanCtorApply @BeanCtorApply} annotation through to the builder's annotation list.
045    * The {@link org.apache.juneau.commons.reflect.AnnotationProvider.Builder#addRuntimeAnnotations(java.util.List) AnnotationProvider.Builder#addRuntimeAnnotations(java.util.List)}
046    * method handles unwrapping the nested {@link BeanCtor @BeanCtor} from {@link BeanCtorApply#value()} and registering it
047    * under the targets specified by {@link BeanCtorApply#on()} and {@link BeanCtorApply#onClass()}.
048    */
049   @SuppressWarnings({
050      "rawtypes" // Raw types required for reflective annotation application.
051   })
052   public static class Applier extends AnnotationApplier<BeanCtorApply,Context.Builder> {
053
054      /**
055       * Constructor.
056       *
057       * @param vr The resolver for resolving values in annotations. Must not be <jk>null</jk>.
058       */
059      public Applier(VarResolverSession vr) {
060         super(BeanCtorApply.class, Context.Builder.class, vr);
061      }
062
063      @Override
064      public void apply(AnnotationInfo<BeanCtorApply> ai, Context.Builder b) {
065         BeanCtorApply a = ai.inner();
066         if (isEmptyArray(a.on()) && isEmptyArray(a.onClass()))
067            return;
068         b.annotations(a);
069      }
070   }
071
072   /**
073    * Builder class.
074    *
075    * <h5 class='section'>See Also:</h5><ul>
076    *    <li class='jm'>{@link MarshallingContext.Builder#annotations(Annotation...)}
077    * </ul>
078    */
079   public static class Builder extends AppliedAnnotationObject.BuilderTMF {
080
081      BeanCtor value = BeanCtorAnnotation.DEFAULT;
082
083      /**
084       * Constructor.
085       */
086      protected Builder() {
087         super(BeanCtorApply.class);
088      }
089
090      /**
091       * Sets the {@link BeanCtorApply#value()} property on this annotation.
092       *
093       * @param value The new value for this property.
094       * @return This object.
095       */
096      public Builder value(BeanCtor value) {
097         this.value = value;
098         return this;
099      }
100
101      @Override /* Overridden from AppliedAnnotationObject.Builder */
102      public Builder on(String...value) {
103         super.on(value);
104         return this;
105      }
106
107      @Override /* Overridden from AppliedAnnotationObject.BuilderT */
108      public Builder on(Class<?>...value) {
109         super.on(value);
110         return this;
111      }
112
113      @Override /* Overridden from AppliedOnClassAnnotationObject.Builder */
114      public Builder onClass(Class<?>...value) {
115         super.onClass(value);
116         return this;
117      }
118
119      @Override /* Overridden from AppliedAnnotationObject.BuilderM */
120      public Builder on(Method...value) {
121         super.on(value);
122         return this;
123      }
124
125      @Override /* Overridden from AppliedAnnotationObject.BuilderMF */
126      public Builder on(Field...value) {
127         super.on(value);
128         return this;
129      }
130
131      @Override /* Overridden from AppliedAnnotationObject.BuilderT */
132      public Builder on(ClassInfo...value) {
133         super.on(value);
134         return this;
135      }
136
137      @Override /* Overridden from AppliedAnnotationObject.BuilderT */
138      public Builder onClass(ClassInfo...value) {
139         super.onClass(value);
140         return this;
141      }
142
143      @Override /* Overridden from AppliedAnnotationObject.BuilderTMF */
144      public Builder on(FieldInfo...value) {
145         super.on(value);
146         return this;
147      }
148
149      @Override /* Overridden from AppliedAnnotationObject.BuilderTMF */
150      public Builder on(MethodInfo...value) {
151         super.on(value);
152         return this;
153      }
154
155      /**
156       * Instantiates a new {@link BeanCtorApply @BeanCtorApply} object initialized with this builder.
157       *
158       * @return A new {@link BeanCtorApply} object.
159       */
160      public BeanCtorApply build() {
161         return new Object(this);
162      }
163   }
164
165   @SuppressWarnings({
166      "java:S2160" // equals() inherited from AnnotationObject compares all annotation interface methods; subclass fields are accessed via those methods
167   })
168   private static class Object extends AppliedOnClassAnnotationObject implements BeanCtorApply {
169
170      private final BeanCtor value;
171
172      Object(BeanCtorApplyAnnotation.Builder b) {
173         super(b);
174         value = b.value;
175      }
176
177      @Override /* Overridden from BeanCtorApply */
178      public BeanCtor value() {
179         return value;
180      }
181   }
182
183   /** Default value */
184   public static final BeanCtorApply DEFAULT = create().build();
185
186   /**
187    * Instantiates a new builder for this class.
188    *
189    * @return A new builder object.
190    */
191   public static Builder create() {
192      return new Builder();
193   }
194
195   /**
196    * Instantiates a new builder for this class.
197    *
198    * @param on The targets this annotation applies to.
199    * @return A new builder object.
200    */
201   public static Builder create(Class<?>...on) {
202      return create().on(on);
203   }
204
205   /**
206    * Instantiates a new builder for this class.
207    *
208    * @param on The targets this annotation applies to.
209    * @return A new builder object.
210    */
211   public static Builder create(String...on) {
212      return create().on(on);
213   }
214
215   /**
216    * Returns <jk>true</jk> if the specified annotation contains all default values.
217    *
218    * @param a The annotation to check. Can be <jk>null</jk> (returns <jk>true</jk>).
219    * @return <jk>true</jk> if the specified annotation contains all default values.
220    */
221   public static boolean empty(BeanCtorApply a) {
222      return a == null || DEFAULT.equals(a);
223   }
224}