1 /*
2  * Copyright (c) 2003, 2016, 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 sun.misc.JavaLangAccess;
29 
30 import java.lang.annotation.*;
31 import java.lang.reflect.*;
32 import java.util.*;
33 import java.security.AccessController;
34 import java.security.PrivilegedAction;
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 assoicated
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      * @throw IllegalArgumentException if the specified class object for
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 = sun.misc.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      * @throw 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         Method[] methods =
109             AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
110                 public Method[] run() {
111                     // Initialize memberTypes and defaultValues
112                     return annotationClass.getDeclaredMethods();
113                 }
114             });
115 
116         memberTypes = new HashMap<String,Class<?>>(methods.length+1, 1.0f);
117         memberDefaults = new HashMap<String, Object>(0);
118         members = new HashMap<String, Method>(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 = sun.misc.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);
152             retention = (ret == null ? RetentionPolicy.CLASS : ret.value());
153             inherited = metaAnnotations.containsKey(Inherited.class);
154         }
155         else {
156             retention = RetentionPolicy.RUNTIME;
157             inherited = false;
158         }
159     }
160 
161     /**
162      * Returns the type that must be returned by the invocation handler
163      * of a dynamic proxy in order to have the dynamic proxy return
164      * the specified type (which is assumed to be a legal member type
165      * for an annotation).
166      */
invocationHandlerReturnType(Class<?> type)167     public static Class<?> invocationHandlerReturnType(Class<?> type) {
168         // Translate primitives to wrappers
169         if (type == byte.class)
170             return Byte.class;
171         if (type == char.class)
172             return Character.class;
173         if (type == double.class)
174             return Double.class;
175         if (type == float.class)
176             return Float.class;
177         if (type == int.class)
178             return Integer.class;
179         if (type == long.class)
180             return Long.class;
181         if (type == short.class)
182             return Short.class;
183         if (type == boolean.class)
184             return Boolean.class;
185 
186         // Otherwise, just return declared type
187         return type;
188     }
189 
190     /**
191      * Returns member types for this annotation type
192      * (member name -> type mapping).
193      */
memberTypes()194     public Map<String, Class<?>> memberTypes() {
195         return memberTypes;
196     }
197 
198     /**
199      * Returns members of this annotation type
200      * (member name -> associated Method object mapping).
201      */
members()202     public Map<String, Method> members() {
203         return members;
204     }
205 
206     /**
207      * Returns the default values for this annotation type
208      * (Member name -> default value mapping).
209      */
memberDefaults()210     public Map<String, Object> memberDefaults() {
211         return memberDefaults;
212     }
213 
214     /**
215      * Returns the retention policy for this annotation type.
216      */
retention()217     public RetentionPolicy retention() {
218         return retention;
219     }
220 
221     /**
222      * Returns true if this this annotation type is inherited.
223      */
isInherited()224     public boolean isInherited() {
225         return inherited;
226     }
227 
228     /**
229      * For debugging.
230      */
toString()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 }
239