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