15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package sun.reflect.annotation;
27
28 import java.lang.annotation.*;
29 import java.lang.reflect.*;
30 import java.util.*;
31 import java.security.AccessController;
32 import java.security.PrivilegedAction;
33 import jdk.internal.misc.SharedSecrets;
34 import jdk.internal.misc.JavaLangAccess;
35
36 /**
37 * Represents an annotation type at run time. Used to type-check annotations
38 * and apply member defaults.
39 *
40 * @author Josh Bloch
41 * @since 1.5
42 */
43 public class AnnotationType {
44 /**
45 * Member name -> type mapping. Note that primitive types
46 * are represented by the class objects for the corresponding wrapper
47 * types. This matches the return value that must be used for a
48 * dynamic proxy, allowing for a simple isInstance test.
49 */
50 private final Map<String, Class<?>> memberTypes;
51
52 /**
53 * Member name -> default value mapping.
54 */
56
57 /**
58 * Member name -> Method object mapping. This (and its associated
59 * accessor) are used only to generate AnnotationTypeMismatchExceptions.
60 */
61 private final Map<String, Method> members;
62
63 /**
64 * The retention policy for this annotation type.
65 */
66 private final RetentionPolicy retention;
67
68 /**
69 * Whether this annotation type is inherited.
70 */
71 private final boolean inherited;
72
73 /**
74 * Returns an AnnotationType instance for the specified annotation type.
75 *
76 * @throws IllegalArgumentException if the specified class object
77 * does not represent a valid annotation type
78 */
79 public static AnnotationType getInstance(
80 Class<? extends Annotation> annotationClass)
81 {
82 JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
83 AnnotationType result = jla.getAnnotationType(annotationClass); // volatile read
84 if (result == null) {
85 result = new AnnotationType(annotationClass);
86 // try to CAS the AnnotationType: null -> result
87 if (!jla.casAnnotationType(annotationClass, null, result)) {
88 // somebody was quicker -> read it's result
89 result = jla.getAnnotationType(annotationClass);
90 assert result != null;
91 }
92 }
93
94 return result;
95 }
96
97 /**
98 * Sole constructor.
99 *
100 * @param annotationClass the class object for the annotation type
101 * @throws IllegalArgumentException if the specified class object for
102 * does not represent a valid annotation type
103 */
104 private AnnotationType(final Class<? extends Annotation> annotationClass) {
105 if (!annotationClass.isAnnotation())
106 throw new IllegalArgumentException("Not an annotation type");
107
108 Method[] methods =
109 AccessController.doPrivileged(new PrivilegedAction<>() {
110 public Method[] run() {
111 // Initialize memberTypes and defaultValues
112 return annotationClass.getDeclaredMethods();
113 }
114 });
115
116 memberTypes = new HashMap<>(methods.length+1, 1.0f);
117 memberDefaults = new HashMap<>(0);
118 members = new HashMap<>(methods.length+1, 1.0f);
119
120 for (Method method : methods) {
121 if (Modifier.isPublic(method.getModifiers()) &&
122 Modifier.isAbstract(method.getModifiers()) &&
123 !method.isSynthetic()) {
124 if (method.getParameterTypes().length != 0) {
125 throw new IllegalArgumentException(method + " has params");
126 }
127 String name = method.getName();
128 Class<?> type = method.getReturnType();
129 memberTypes.put(name, invocationHandlerReturnType(type));
130 members.put(name, method);
131
132 Object defaultValue = method.getDefaultValue();
133 if (defaultValue != null) {
134 memberDefaults.put(name, defaultValue);
135 }
136 }
137 }
138
139 // Initialize retention, & inherited fields. Special treatment
140 // of the corresponding annotation types breaks infinite recursion.
141 if (annotationClass != Retention.class &&
142 annotationClass != Inherited.class) {
143 JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
144 Map<Class<? extends Annotation>, Annotation> metaAnnotations =
145 AnnotationParser.parseSelectAnnotations(
146 jla.getRawClassAnnotations(annotationClass),
147 jla.getConstantPool(annotationClass),
148 annotationClass,
149 Retention.class, Inherited.class
150 );
151 Retention ret = (Retention) metaAnnotations.get(Retention.class);
186 // Otherwise, just return declared type
187 return type;
188 }
189
190 /**
191 * Returns member types for this annotation type
192 * (member name {@literal ->} type mapping).
193 */
194 public Map<String, Class<?>> memberTypes() {
195 return memberTypes;
196 }
197
198 /**
199 * Returns members of this annotation type
200 * (member name {@literal ->} associated Method object mapping).
201 */
202 public Map<String, Method> members() {
203 return members;
204 }
205
206 /**
207 * Returns the default values for this annotation type
208 * (Member name {@literal ->} default value mapping).
209 */
210 public Map<String, Object> memberDefaults() {
211 return memberDefaults;
212 }
213
214 /**
215 * Returns the retention policy for this annotation type.
216 */
217 public RetentionPolicy retention() {
218 return retention;
219 }
220
221 /**
222 * Returns true if this annotation type is inherited.
223 */
224 public boolean isInherited() {
225 return inherited;
226 }
227
228 /**
229 * For debugging.
230 */
231 public String toString() {
232 return "Annotation Type:\n" +
233 " Member types: " + memberTypes + "\n" +
234 " Member defaults: " + memberDefaults + "\n" +
235 " Retention policy: " + retention + "\n" +
236 " Inherited: " + inherited;
237 }
238 }
|
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package sun.reflect.annotation;
27
28 import java.lang.annotation.*;
29 import java.lang.reflect.*;
30 import java.util.*;
31 import java.security.AccessController;
32 import java.security.PrivilegedAction;
33 import jdk.internal.misc.SharedSecrets;
34 import jdk.internal.misc.JavaLangAccess;
35 import jdk.internal.reflect.ReflectionFactory;
36
37 /**
38 * Represents an annotation type at run time. Used to type-check annotations
39 * and apply member defaults.
40 *
41 * @author Josh Bloch
42 * @since 1.5
43 */
44 public class AnnotationType {
45 /**
46 * Member name -> type mapping. Note that primitive types
47 * are represented by the class objects for the corresponding wrapper
48 * types. This matches the return value that must be used for a
49 * dynamic proxy, allowing for a simple isInstance test.
50 */
51 private final Map<String, Class<?>> memberTypes;
52
53 /**
54 * Member name -> default value mapping.
55 */
57
58 /**
59 * Member name -> Method object mapping. This (and its associated
60 * accessor) are used only to generate AnnotationTypeMismatchExceptions.
61 */
62 private final Map<String, Method> members;
63
64 /**
65 * The retention policy for this annotation type.
66 */
67 private final RetentionPolicy retention;
68
69 /**
70 * Whether this annotation type is inherited.
71 */
72 private final boolean inherited;
73
74 /**
75 * Returns an AnnotationType instance for the specified annotation type.
76 *
77 * @throws AnnotationFormatError if the specified class object
78 * does not represent a valid annotation type
79 */
80 public static AnnotationType getInstance(
81 Class<? extends Annotation> annotationClass)
82 {
83 JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
84 AnnotationType result = jla.getAnnotationType(annotationClass); // volatile read
85 if (result == null) {
86 result = new AnnotationType(annotationClass);
87 // try to CAS the AnnotationType: null -> result
88 if (!jla.casAnnotationType(annotationClass, null, result)) {
89 // somebody was quicker -> read it's result
90 result = jla.getAnnotationType(annotationClass);
91 assert result != null;
92 }
93 }
94
95 return result;
96 }
97
98 /**
99 * Sole constructor.
100 *
101 * @param annotationClass the class object for the annotation type
102 * @throws AnnotationFormatError if the specified class object
103 * does not represent a valid annotation type
104 */
105 private AnnotationType(final Class<? extends Annotation> annotationClass) {
106 Class<?>[] superInterfaces = annotationClass.getInterfaces();
107 if (!annotationClass.isAnnotation() ||
108 superInterfaces.length != 1 ||
109 superInterfaces[0] != Annotation.class) {
110 throw new AnnotationFormatError("Not an annotation type.");
111 }
112
113 Method[] methods =
114 AccessController.doPrivileged(new PrivilegedAction<>() {
115 public Method[] run() {
116 return annotationClass.getDeclaredMethods();
117 }
118 });
119
120 memberTypes = new HashMap<>(methods.length+1, 1.0f);
121 memberDefaults = new HashMap<>(0);
122 members = new HashMap<>(methods.length+1, 1.0f);
123
124 for (Method method : methods) {
125 // skip synthetic methods as would be created for lambdas for example
126 if (!method.isSynthetic()) {
127 validateAnnotationMethod(method);
128 String name = method.getName();
129 Class<?> type = method.getReturnType();
130 memberTypes.put(name, invocationHandlerReturnType(type));
131 members.put(name, method);
132 Object defaultValue = method.getDefaultValue();
133 if (defaultValue != null) {
134 memberDefaults.put(name, defaultValue);
135 }
136 }
137 }
138
139 // Initialize retention, & inherited fields. Special treatment
140 // of the corresponding annotation types breaks infinite recursion.
141 if (annotationClass != Retention.class &&
142 annotationClass != Inherited.class) {
143 JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
144 Map<Class<? extends Annotation>, Annotation> metaAnnotations =
145 AnnotationParser.parseSelectAnnotations(
146 jla.getRawClassAnnotations(annotationClass),
147 jla.getConstantPool(annotationClass),
148 annotationClass,
149 Retention.class, Inherited.class
150 );
151 Retention ret = (Retention) metaAnnotations.get(Retention.class);
186 // Otherwise, just return declared type
187 return type;
188 }
189
190 /**
191 * Returns member types for this annotation type
192 * (member name {@literal ->} type mapping).
193 */
194 public Map<String, Class<?>> memberTypes() {
195 return memberTypes;
196 }
197
198 /**
199 * Returns members of this annotation type
200 * (member name {@literal ->} associated Method object mapping).
201 */
202 public Map<String, Method> members() {
203 return members;
204 }
205
206 private volatile Map<String, Method> accessibleMembers;
207
208 /**
209 * Returns members of this annotation type
210 * (member name {@literal ->} associated Method object mapping)
211 * which are made {@link Method#setAccessible(boolean) accessible}.
212 */
213 Map<String, Method> accessibleMembers() {
214 Map<String, Method> accMembers = accessibleMembers;
215 if (accMembers == null) {
216 accMembers = AccessController.doPrivileged(new PrivilegedAction<>() {
217 @Override
218 public Map<String, Method> run() {
219 Map<String, Method> ams = new HashMap<>(members.size()+1, 1.0f);
220 ReflectionFactory rf = ReflectionFactory.getReflectionFactory();
221 for (Method m : members.values()) {
222 Method am = rf.leafCopyMethod(m);
223 am.setAccessible(true);
224 ams.put(am.getName(), am);
225 }
226 return ams;
227 }
228 });
229 accessibleMembers = accMembers;
230 }
231 return accMembers;
232 }
233
234 /**
235 * Returns the default values for this annotation type
236 * (Member name {@literal ->} default value mapping).
237 */
238 public Map<String, Object> memberDefaults() {
239 return memberDefaults;
240 }
241
242 /**
243 * Returns the retention policy for this annotation type.
244 */
245 public RetentionPolicy retention() {
246 return retention;
247 }
248
249 /**
250 * Returns true if this annotation type is inherited.
251 */
252 public boolean isInherited() {
253 return inherited;
254 }
255
256 /**
257 * For debugging.
258 */
259 public String toString() {
260 return "Annotation Type:\n" +
261 " Member types: " + memberTypes + "\n" +
262 " Member defaults: " + memberDefaults + "\n" +
263 " Retention policy: " + retention + "\n" +
264 " Inherited: " + inherited;
265 }
266
267 /**
268 * Validates that specified method is structurally appropriate for an
269 * annotation type. As of Java SE 8, annotation types cannot
270 * contain static methods and the declared methods of an
271 * annotation type must take zero arguments and there are
272 * restrictions on the return type.
273 * @throws AnnotationFormatError if specified method is
274 * inappropriate method for an annotation type.
275 */
276 private static void validateAnnotationMethod(Method method) {
277 /*
278 * Specification citations below are from JLS
279 * 9.6.1. Annotation Type Elements
280 */
281 boolean valid = true;
282 block: {
283 /*
284 * "By virtue of the AnnotationTypeElementDeclaration
285 * production, a method declaration in an annotation type
286 * declaration cannot have formal parameters, type
287 * parameters, or a throws clause.
288 *
289 * "By virtue of the AnnotationTypeElementModifier
290 * production, a method declaration in an annotation type
291 * declaration cannot be default or static."
292 */
293 if (method.getModifiers() != (Modifier.PUBLIC | Modifier.ABSTRACT) ||
294 method.isDefault() ||
295 method.getParameterCount() != 0 ||
296 method.getExceptionTypes().length != 0) {
297 valid = false;
298 break block;
299 }
300
301 /*
302 * "It is a compile-time error if the return type of a
303 * method declared in an annotation type is not one of the
304 * following: a primitive type, String, Class, any
305 * parameterized invocation of Class, an enum type
306 * (section 8.9), an annotation type, or an array type
307 * (chapter 10) whose element type is one of the preceding
308 * types."
309 */
310 Class<?> returnType = method.getReturnType();
311 if (returnType.isArray()) {
312 returnType = returnType.getComponentType();
313 if (returnType.isArray()) { // Only single dimensional arrays
314 valid = false;
315 break block;
316 }
317 }
318
319 if (!((returnType.isPrimitive() && returnType != void.class) ||
320 returnType == java.lang.String.class ||
321 returnType == java.lang.Class.class ||
322 returnType.isEnum() ||
323 returnType.isAnnotation())) {
324 valid = false;
325 break block;
326 }
327
328 /*
329 * "It is a compile-time error if any method declared in an
330 * annotation type has a signature that is
331 * override-equivalent to that of any public or protected
332 * method declared in class Object or in the interface
333 * java.lang.annotation.Annotation."
334 *
335 * The methods in Object or Annotation meeting the other
336 * criteria (no arguments, contrained return type, etc.)
337 * above are:
338 *
339 * String toString()
340 * int hashCode()
341 * Class<? extends Annotation> annotationType()
342 */
343 String methodName = method.getName();
344 if ((methodName.equals("toString") && returnType == java.lang.String.class) ||
345 (methodName.equals("hashCode") && returnType == int.class) ||
346 (methodName.equals("annotationType") && returnType == java.lang.Class.class)) {
347 valid = false;
348 break block;
349 }
350 }
351
352 if (!valid) {
353 throw new AnnotationFormatError(
354 "Malformed method on an annotation type: " + method);
355 }
356 }
357 }
|