View Javadoc
1   /*
2    * Copyright (c) 2003, 2013, 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       */
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      */
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 (method.getParameterTypes().length != 0)
122                 throw new IllegalArgumentException(method + " has params");
123             String name = method.getName();
124             Class<?> type = method.getReturnType();
125             memberTypes.put(name, invocationHandlerReturnType(type));
126             members.put(name, method);
127 
128             Object defaultValue = method.getDefaultValue();
129             if (defaultValue != null)
130                 memberDefaults.put(name, defaultValue);
131         }
132 
133         // Initialize retention, & inherited fields.  Special treatment
134         // of the corresponding annotation types breaks infinite recursion.
135         if (annotationClass != Retention.class &&
136             annotationClass != Inherited.class) {
137             JavaLangAccess jla = sun.misc.SharedSecrets.getJavaLangAccess();
138             Map<Class<? extends Annotation>, Annotation> metaAnnotations =
139                 AnnotationParser.parseSelectAnnotations(
140                     jla.getRawClassAnnotations(annotationClass),
141                     jla.getConstantPool(annotationClass),
142                     annotationClass,
143                     Retention.class, Inherited.class
144                 );
145             Retention ret = (Retention) metaAnnotations.get(Retention.class);
146             retention = (ret == null ? RetentionPolicy.CLASS : ret.value());
147             inherited = metaAnnotations.containsKey(Inherited.class);
148         }
149         else {
150             retention = RetentionPolicy.RUNTIME;
151             inherited = false;
152         }
153     }
154 
155     /**
156      * Returns the type that must be returned by the invocation handler
157      * of a dynamic proxy in order to have the dynamic proxy return
158      * the specified type (which is assumed to be a legal member type
159      * for an annotation).
160      */
161     public static Class<?> invocationHandlerReturnType(Class<?> type) {
162         // Translate primitives to wrappers
163         if (type == byte.class)
164             return Byte.class;
165         if (type == char.class)
166             return Character.class;
167         if (type == double.class)
168             return Double.class;
169         if (type == float.class)
170             return Float.class;
171         if (type == int.class)
172             return Integer.class;
173         if (type == long.class)
174             return Long.class;
175         if (type == short.class)
176             return Short.class;
177         if (type == boolean.class)
178             return Boolean.class;
179 
180         // Otherwise, just return declared type
181         return type;
182     }
183 
184     /**
185      * Returns member types for this annotation type
186      * (member name -> type mapping).
187      */
188     public Map<String, Class<?>> memberTypes() {
189         return memberTypes;
190     }
191 
192     /**
193      * Returns members of this annotation type
194      * (member name -> associated Method object mapping).
195      */
196     public Map<String, Method> members() {
197         return members;
198     }
199 
200     /**
201      * Returns the default values for this annotation type
202      * (Member name -> default value mapping).
203      */
204     public Map<String, Object> memberDefaults() {
205         return memberDefaults;
206     }
207 
208     /**
209      * Returns the retention policy for this annotation type.
210      */
211     public RetentionPolicy retention() {
212         return retention;
213     }
214 
215     /**
216      * Returns true if this this annotation type is inherited.
217      */
218     public boolean isInherited() {
219         return inherited;
220     }
221 
222     /**
223      * For debugging.
224      */
225     public String toString() {
226         return "Annotation Type:\n" +
227                "   Member types: " + memberTypes + "\n" +
228                "   Member defaults: " + memberDefaults + "\n" +
229                "   Retention policy: " + retention + "\n" +
230                "   Inherited: " + inherited;
231     }
232 }