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.commons.annotation;
018
019import static org.apache.juneau.commons.utils.AssertionUtils.*;
020import static org.apache.juneau.commons.utils.CollectionUtils.*;
021import static org.apache.juneau.commons.utils.Utils.*;
022
023import java.lang.annotation.*;
024import java.lang.reflect.*;
025import java.util.*;
026import java.util.function.*;
027
028import org.apache.juneau.commons.utils.*;
029
030/**
031 * A concrete implementation of a Java annotation that can be created programmatically at runtime.
032 *
033 * <p>
034 * This class provides a base for creating annotation instances without requiring them to be declared on
035 * program elements at compile-time. It allows annotations to be constructed using a builder pattern and
036 * follows all standard Java annotation semantics for equality, hashcode, and string representation.
037 *
038 * <h5 class='section'>Overview:</h5>
039 * <p>
040 * Java annotations are typically declared statically on classes, methods, fields, etc. at compile-time:
041 * <p class='bjava'>
042 *    <ja>@Bean</ja>(sort=<jk>true</jk>)
043 *    <jk>public class</jk> MyClass {...}
044 * </p>
045 *
046 * <p>
047 * This class allows you to create those same annotations programmatically:
048 * <p class='bjava'>
049 *    Bean <jv>annotation</jv> = BeanAnnotation
050 *       .<jsm>create</jsm>()
051 *       .sort(<jk>true</jk>)
052 *       .build();
053 * </p>
054 *
055 * <h5 class='section'>Equality and Hashcode:</h5>
056 * <p>
057 * Follows the standard Java conventions for annotation equality and hashcode calculation as defined in
058 * {@link Annotation#equals(Object)} and {@link Annotation#hashCode()}. This ensures that programmatically-created
059 * annotations are equivalent to compile-time declared annotations if they have the same type and properties.
060 *
061 * <p class='bjava'>
062 *    <jc>// These two annotations are equal:</jc>
063 *    <ja>@Bean</ja>(sort=<jk>true</jk>)
064 *    <jk>class</jk> MyClass {}
065 *
066 *    Bean <jv>declared</jv> = MyClass.<jk>class</jk>.getAnnotation(Bean.<jk>class</jk>);
067 *    Bean <jv>programmatic</jv> = BeanAnnotation.<jsm>create</jsm>().sort(<jk>true</jk>).build();
068 *
069 *    <jsm>assertEquals</jsm>(<jv>declared</jv>, <jv>programmatic</jv>);  <jc>// true</jc>
070 *    <jsm>assertEquals</jsm>(<jv>declared</jv>.hashCode(), <jv>programmatic</jv>.hashCode());  <jc>// true</jc>
071 * </p>
072 *
073 * <h5 class='section'>Hashcode Caching:</h5>
074 * <p>
075 * For performance reasons, the hashcode is calculated once and cached on first access.
076 * The hash is computed lazily when {@link #hashCode()} is first called and then stored for subsequent calls.
077 *
078 * <p class='bjava'>
079 *    <jk>public</jk> MyAnnotation(Builder <jv>builder</jv>) {
080 *       <jk>super</jk>(<jv>builder</jv>);
081 *       <jk>this</jk>.<jf>myField</jf> = <jv>builder</jv>.<jf>myField</jf>;
082 *    }
083 * </p>
084 *
085 * <h5 class='section'>Builder Pattern:</h5>
086 * <p>
087 * Subclasses should provide a nested {@link Builder} class that extends {@link AnnotationObject.Builder}
088 * to construct instances using a fluent builder pattern. The builder should:
089 * <ul class='spaced-list'>
090 *    <li>Provide setter methods for each annotation property
091 *    <li>Return <c>this</c> (or the builder type) from each setter for method chaining
092 *    <li>Provide a {@code build()} method that constructs the final annotation object
093 * </ul>
094 *
095 * <h5 class='section'>Example Implementation:</h5>
096 * <p class='bjava'>
097 *    <jk>public class</jk> MyAnnotationObject <jk>extends</jk> AnnotationObject <jk>implements</jk> MyAnnotation {
098 *
099 *       <jk>private final</jk> String <jf>value</jf>;
100 *
101 *       <jk>public static class</jk> Builder <jk>extends</jk> AnnotationObject.Builder {
102 *          String <jf>value</jf> = <js>""</js>;
103 *
104 *          <jk>public</jk> Builder() {
105 *             <jk>super</jk>(MyAnnotation.<jk>class</jk>);
106 *          }
107 *
108 *          <jk>public</jk> Builder value(String <jv>value</jv>) {
109 *             <jk>this</jk>.<jf>value</jf> = <jv>value</jv>;
110 *             <jk>return this</jk>;
111 *          }
112 *
113 *          <jk>public</jk> MyAnnotation build() {
114 *             <jk>return new</jk> MyAnnotationObject(<jk>this</jk>);
115 *          }
116 *       }
117 *
118 *       <jk>public</jk> MyAnnotationObject(Builder <jv>builder</jv>) {
119 *          <jk>super</jk>(<jv>builder</jv>);
120 *          <jk>this</jk>.<jf>value</jf> = <jv>builder</jv>.<jf>value</jf>;
121 *       }
122 *
123 *       <ja>@Override</ja>
124 *       <jk>public</jk> String value() {
125 *          <jk>return</jk> <jf>value</jf>;
126 *       }
127 *    }
128 * </p>
129 *
130 * <h5 class='section'>See Also:</h5><ul>
131 *    <li class='jc'>{@link AppliedAnnotationObject} - For annotations with dynamic targeting support
132 *    <li class='link'><a class="doclink" href="../../../../../overview-summary.html#juneau-commons.Annotations">Overview &gt; juneau-commons &gt; Annotations</a>
133 * </ul>
134 */
135public class AnnotationObject implements Annotation {
136
137   //-----------------------------------------------------------------------------------------------------------------
138   // Static
139   //-----------------------------------------------------------------------------------------------------------------
140
141   /**
142    * Builder for {@link AnnotationObject} objects.
143    */
144   public static class Builder {
145
146      private Class<? extends Annotation> annotationType;
147
148      /**
149       * Constructor.
150       *
151       * @param annotationType The annotation type of the annotation implementation class.
152       */
153      public Builder(Class<? extends Annotation> annotationType) {
154         this.annotationType = assertArgNotNull("annotationType", annotationType);
155      }
156
157      /**
158       * Returns the annotation type being built.
159       *
160       * @return The annotation type being built.
161       */
162      public Class<? extends Annotation> getAnnotationType() { return annotationType; }
163   }
164
165   //-----------------------------------------------------------------------------------------------------------------
166   // Instance
167   //-----------------------------------------------------------------------------------------------------------------
168
169   private final Class<? extends Annotation> annotationType;
170   private Supplier<Integer> hashCode = mem(() -> AnnotationUtils.hash(this));
171
172   /**
173    * Constructor.
174    *
175    * @param b The builder used to instantiate the fields of this class.
176    */
177   public AnnotationObject(Builder b) {
178      assertArgNotNull("b", b);
179      annotationType = b.getAnnotationType();
180   }
181
182   /**
183    * Implements the {@link Annotation#annotationType()} method for child classes.
184    *
185    * @return This class.
186    */
187   @Override /* Overridden from Annotation */
188   public Class<? extends Annotation> annotationType() {
189      return annotationType;
190   }
191
192   @Override /* Overridden from Object */
193   public boolean equals(Object o) {
194      return o instanceof Annotation o2 && annotationType.isInstance(o) && eq(this, o2);
195   }
196
197   @Override /* Overridden from Object */
198   public int hashCode() {
199      return hashCode.get();
200   }
201
202   /**
203    * Returns this annotation as a map of key/value pairs.
204    *
205    * <p>
206    * Useful for debugging.
207    *
208    * @return This annotation as a map of key/value pairs.
209    */
210   protected Map<String,Object> propertyMap() {
211      // @formatter:off
212      var m = mapb_so().sorted().build();
213      stream(annotationType().getDeclaredMethods())
214         // Note: isAnnotation() check is defensive code. For properly-formed AnnotationObject instances,
215         // annotationType() always returns an annotation interface, so this condition is always true.
216         .filter(x->x.getParameterCount() == 0 && x.getDeclaringClass().isAnnotation())
217         .sorted(Comparator.comparing(Method::getName))
218         .forEach(x -> m.put(x.getName(), safeSupplier(()->x.invoke(this))));
219      return m;
220      // @formatter:on
221   }
222
223   @Override /* Overridden from Object */
224   public String toString() {
225      return r(propertyMap());
226   }
227}