1 /*
2  * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
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.access.SharedSecrets;
34 import jdk.internal.access.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      */
55     private final Map<String, Object> memberDefaults;
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      */
getInstance( Class<? extends Annotation> annotationClass)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      */
AnnotationType(final Class<? extends Annotation> annotationClass)104     private AnnotationType(final Class<? extends Annotation> annotationClass) {
105         if (!annotationClass.isAnnotation())
106             throw new IllegalArgumentException("Not an annotation type");
107 
108         @SuppressWarnings("removal")
109         Method[] methods =
110             AccessController.doPrivileged(new PrivilegedAction<>() {
111                 public Method[] run() {
112                     // Initialize memberTypes and defaultValues
113                     return annotationClass.getDeclaredMethods();
114                 }
115             });
116 
117         memberTypes = new HashMap<>(methods.length+1, 1.0f);
118         memberDefaults = new HashMap<>(0);
119         members = new HashMap<>(methods.length+1, 1.0f);
120 
121         for (Method method : methods) {
122             if (Modifier.isPublic(method.getModifiers()) &&
123                 Modifier.isAbstract(method.getModifiers()) &&
124                 !method.isSynthetic()) {
125                 if (method.getParameterCount() != 0) {
126                     throw new IllegalArgumentException(method + " has params");
127                 }
128                 String name = method.getName();
129                 Class<?> type = method.getReturnType();
130                 memberTypes.put(name, invocationHandlerReturnType(type));
131                 members.put(name, method);
132 
133                 Object defaultValue = method.getDefaultValue();
134                 if (defaultValue != null) {
135                     memberDefaults.put(name, defaultValue);
136                 }
137             }
138         }
139 
140         // Initialize retention, & inherited fields.  Special treatment
141         // of the corresponding annotation types breaks infinite recursion.
142         if (annotationClass != Retention.class &&
143             annotationClass != Inherited.class) {
144             JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
145             Map<Class<? extends Annotation>, Annotation> metaAnnotations =
146                 AnnotationParser.parseSelectAnnotations(
147                     jla.getRawClassAnnotations(annotationClass),
148                     jla.getConstantPool(annotationClass),
149                     annotationClass,
150                     Retention.class, Inherited.class
151                 );
152             Retention ret = (Retention) metaAnnotations.get(Retention.class);
153             retention = (ret == null ? RetentionPolicy.CLASS : ret.value());
154             inherited = metaAnnotations.containsKey(Inherited.class);
155         }
156         else {
157             retention = RetentionPolicy.RUNTIME;
158             inherited = false;
159         }
160     }
161 
162     /**
163      * Returns the type that must be returned by the invocation handler
164      * of a dynamic proxy in order to have the dynamic proxy return
165      * the specified type (which is assumed to be a legal member type
166      * for an annotation).
167      */
invocationHandlerReturnType(Class<?> type)168     public static Class<?> invocationHandlerReturnType(Class<?> type) {
169         // Translate primitives to wrappers
170         if (type == byte.class)
171             return Byte.class;
172         if (type == char.class)
173             return Character.class;
174         if (type == double.class)
175             return Double.class;
176         if (type == float.class)
177             return Float.class;
178         if (type == int.class)
179             return Integer.class;
180         if (type == long.class)
181             return Long.class;
182         if (type == short.class)
183             return Short.class;
184         if (type == boolean.class)
185             return Boolean.class;
186 
187         // Otherwise, just return declared type
188         return type;
189     }
190 
191     /**
192      * Returns member types for this annotation type
193      * (member name {@literal ->} type mapping).
194      */
memberTypes()195     public Map<String, Class<?>> memberTypes() {
196         return memberTypes;
197     }
198 
199     /**
200      * Returns members of this annotation type
201      * (member name {@literal ->} associated Method object mapping).
202      */
members()203     public Map<String, Method> members() {
204         return members;
205     }
206 
207     /**
208      * Returns the default values for this annotation type
209      * (Member name {@literal ->} default value mapping).
210      */
memberDefaults()211     public Map<String, Object> memberDefaults() {
212         return memberDefaults;
213     }
214 
215     /**
216      * Returns the retention policy for this annotation type.
217      */
retention()218     public RetentionPolicy retention() {
219         return retention;
220     }
221 
222     /**
223      * Returns true if this annotation type is inherited.
224      */
isInherited()225     public boolean isInherited() {
226         return inherited;
227     }
228 
229     /**
230      * For debugging.
231      */
toString()232     public String toString() {
233         return "Annotation Type:\n" +
234                "   Member types: " + memberTypes + "\n" +
235                "   Member defaults: " + memberDefaults + "\n" +
236                "   Retention policy: " + retention + "\n" +
237                "   Inherited: " + inherited;
238     }
239 }
240