blob: f23263d8c05ff62a72aef4be52fdbe980b100e6d [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.reflect.annotation;
27
28import java.lang.annotation.*;
29import java.lang.reflect.*;
30import java.util.*;
31import java.security.AccessController;
32import java.security.PrivilegedAction;
33
34/**
35 * Represents an annotation type at run time. Used to type-check annotations
36 * and apply member defaults.
37 *
38 * @author Josh Bloch
39 * @since 1.5
40 */
41public class AnnotationType {
42 /**
43 * Member name -> type mapping. Note that primitive types
44 * are represented by the class objects for the corresponding wrapper
45 * types. This matches the return value that must be used for a
46 * dynamic proxy, allowing for a simple isInstance test.
47 */
48 private final Map<String, Class> memberTypes = new HashMap<String,Class>();
49
50 /**
51 * Member name -> default value mapping.
52 */
53 private final Map<String, Object> memberDefaults =
54 new HashMap<String, Object>();
55
56 /**
57 * Member name -> Method object mapping. This (and its assoicated
58 * accessor) are used only to generate AnnotationTypeMismatchExceptions.
59 */
60 private final Map<String, Method> members = new HashMap<String, Method>();
61
62 /**
63 * The retention policy for this annotation type.
64 */
65 private RetentionPolicy retention = RetentionPolicy.RUNTIME;;
66
67 /**
68 * Whether this annotation type is inherited.
69 */
70 private boolean inherited = false;
71
72 /**
73 * Returns an AnnotationType instance for the specified annotation type.
74 *
75 * @throw IllegalArgumentException if the specified class object for
76 * does not represent a valid annotation type
77 */
78 public static synchronized AnnotationType getInstance(
79 Class annotationClass)
80 {
81 AnnotationType result = sun.misc.SharedSecrets.getJavaLangAccess().
82 getAnnotationType(annotationClass);
83 if (result == null)
84 result = new AnnotationType((Class<?>) annotationClass);
85
86 return result;
87 }
88
89 /**
90 * Sole constructor.
91 *
92 * @param annotationClass the class object for the annotation type
93 * @throw IllegalArgumentException if the specified class object for
94 * does not represent a valid annotation type
95 */
96 private AnnotationType(final Class<?> annotationClass) {
97 if (!annotationClass.isAnnotation())
98 throw new IllegalArgumentException("Not an annotation type");
99
100 Method[] methods =
101 AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
102 public Method[] run() {
103 // Initialize memberTypes and defaultValues
104 return annotationClass.getDeclaredMethods();
105 }
106 });
107
108
109 for (Method method : methods) {
110 if (method.getParameterTypes().length != 0)
111 throw new IllegalArgumentException(method + " has params");
112 String name = method.getName();
113 Class type = method.getReturnType();
114 memberTypes.put(name, invocationHandlerReturnType(type));
115 members.put(name, method);
116
117 Object defaultValue = method.getDefaultValue();
118 if (defaultValue != null)
119 memberDefaults.put(name, defaultValue);
120
121 members.put(name, method);
122 }
123
124 sun.misc.SharedSecrets.getJavaLangAccess().
125 setAnnotationType(annotationClass, this);
126
127 // Initialize retention, & inherited fields. Special treatment
128 // of the corresponding annotation types breaks infinite recursion.
129 if (annotationClass != Retention.class &&
130 annotationClass != Inherited.class) {
131 Retention ret = annotationClass.getAnnotation(Retention.class);
132 retention = (ret == null ? RetentionPolicy.CLASS : ret.value());
133 inherited = annotationClass.isAnnotationPresent(Inherited.class);
134 }
135 }
136
137 /**
138 * Returns the type that must be returned by the invocation handler
139 * of a dynamic proxy in order to have the dynamic proxy return
140 * the specified type (which is assumed to be a legal member type
141 * for an annotation).
142 */
143 public static Class invocationHandlerReturnType(Class type) {
144 // Translate primitives to wrappers
145 if (type == byte.class)
146 return Byte.class;
147 if (type == char.class)
148 return Character.class;
149 if (type == double.class)
150 return Double.class;
151 if (type == float.class)
152 return Float.class;
153 if (type == int.class)
154 return Integer.class;
155 if (type == long.class)
156 return Long.class;
157 if (type == short.class)
158 return Short.class;
159 if (type == boolean.class)
160 return Boolean.class;
161
162 // Otherwise, just return declared type
163 return type;
164 }
165
166 /**
167 * Returns member types for this annotation type
168 * (member name -> type mapping).
169 */
170 public Map<String, Class> memberTypes() {
171 return memberTypes;
172 }
173
174 /**
175 * Returns members of this annotation type
176 * (member name -> associated Method object mapping).
177 */
178 public Map<String, Method> members() {
179 return members;
180 }
181
182 /**
183 * Returns the default values for this annotation type
184 * (Member name -> default value mapping).
185 */
186 public Map<String, Object> memberDefaults() {
187 return memberDefaults;
188 }
189
190 /**
191 * Returns the retention policy for this annotation type.
192 */
193 public RetentionPolicy retention() {
194 return retention;
195 }
196
197 /**
198 * Returns true if this this annotation type is inherited.
199 */
200 public boolean isInherited() {
201 return inherited;
202 }
203
204 /**
205 * For debugging.
206 */
207 public String toString() {
208 StringBuffer s = new StringBuffer("Annotation Type:" + "\n");
209 s.append(" Member types: " + memberTypes + "\n");
210 s.append(" Member defaults: " + memberDefaults + "\n");
211 s.append(" Retention policy: " + retention + "\n");
212 s.append(" Inherited: " + inherited);
213 return s.toString();
214 }
215}