Merged with tip.
[cacao.git] / src / classes / gnuclasspath / sun / reflect / annotation / AnnotationType.java
1 /*
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
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
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  */
41 public class AnnotationType {
42     /**
43      * Annotation class -> AnnotationType mapping. This emulates
44      * sun.misc.SharedSecrets.getJavaLangAccess().getAnnotationType() and
45      * sun.misc.SharedSecrets.getJavaLangAccess().setAnnotationType() so
46      * this class can be used with gnu classpath.
47      *
48      * @author Mathias Panzenboeck
49      */
50     private static Map<Class, AnnotationType> annotationTypes =
51         new HashMap<Class, AnnotationType>();
52
53     /**
54      * Member name -> type mapping. Note that primitive types
55      * are represented by the class objects for the corresponding wrapper
56      * types.  This matches the return value that must be used for a
57      * dynamic proxy, allowing for a simple isInstance test.
58      */
59     private final Map<String, Class> memberTypes = new HashMap<String,Class>();
60
61     /**
62      * Member name -> default value mapping.
63      */
64     private final Map<String, Object> memberDefaults =
65         new HashMap<String, Object>();
66
67     /**
68      * Member name -> Method object mapping. This (and its assoicated
69      * accessor) are used only to generate AnnotationTypeMismatchExceptions.
70      */
71     private final Map<String, Method> members = new HashMap<String, Method>();
72
73     /**
74      * The retention policy for this annotation type.
75      */
76     private RetentionPolicy retention = RetentionPolicy.RUNTIME;;
77
78     /**
79      * Whether this annotation type is inherited.
80      */
81     private boolean inherited = false;
82
83     /**
84      * Returns an AnnotationType instance for the specified annotation type.
85      *
86      * @throw IllegalArgumentException if the specified class object for
87      *     does not represent a valid annotation type
88      */
89     public static synchronized AnnotationType getInstance(
90         Class annotationClass)
91     {
92         /*
93         AnnotationType result = sun.misc.SharedSecrets.getJavaLangAccess(). 
94             getAnnotationType(annotationClass); 
95         */
96         // emulating OpenJDKs SharedSecrets in GNU Classpath:
97         AnnotationType result = annotationTypes.get(annotationClass); 
98         if (result == null)
99             result = new AnnotationType((Class<?>) annotationClass);
100
101         return result;
102     }
103
104     /**
105      * Sole constructor.
106      *
107      * @param annotationClass the class object for the annotation type
108      * @throw IllegalArgumentException if the specified class object for
109      *     does not represent a valid annotation type
110      */
111     private AnnotationType(final Class<?> annotationClass) {
112         if (!annotationClass.isAnnotation())
113             throw new IllegalArgumentException("Not an annotation type");
114
115         Method[] methods =      
116             AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
117                 public Method[] run() {
118                     // Initialize memberTypes and defaultValues
119                     return annotationClass.getDeclaredMethods();
120                 }
121             });
122
123
124         for (Method method :  methods) {
125             if (method.getParameterTypes().length != 0)
126                 throw new IllegalArgumentException(method + " has params");
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             members.put(name, method);
137         }
138
139         /*
140         sun.misc.SharedSecrets.getJavaLangAccess(). 
141             setAnnotationType(annotationClass, this); 
142         */
143         // emulating OpenJDKs SharedSecrets in GNU Classpath:
144         annotationTypes.put(annotationClass, this);
145
146         // Initialize retention, & inherited fields.  Special treatment
147         // of the corresponding annotation types breaks infinite recursion.
148         if (annotationClass != Retention.class &&
149             annotationClass != Inherited.class) {
150             Retention ret = annotationClass.getAnnotation(Retention.class);
151             retention = (ret == null ? RetentionPolicy.CLASS : ret.value());
152             inherited = annotationClass.isAnnotationPresent(Inherited.class);
153         }
154     }
155
156     /**
157      * Returns the type that must be returned by the invocation handler
158      * of a dynamic proxy in order to have the dynamic proxy return
159      * the specified type (which is assumed to be a legal member type
160      * for an annotation).
161      */
162     public static Class invocationHandlerReturnType(Class type) {
163         // Translate primitives to wrappers
164         if (type == byte.class)
165             return Byte.class;
166         if (type == char.class)
167             return Character.class;
168         if (type == double.class)
169             return Double.class;
170         if (type == float.class)
171             return Float.class;
172         if (type == int.class)
173             return Integer.class;
174         if (type == long.class)
175             return Long.class;
176         if (type == short.class)
177             return Short.class;
178         if (type == boolean.class)
179             return Boolean.class;
180
181         // Otherwise, just return declared type
182         return type;
183     }
184
185     /**
186      * Returns member types for this annotation type
187      * (member name -> type mapping).
188      */
189     public Map<String, Class> memberTypes() {
190         return memberTypes;
191     }
192
193     /**
194      * Returns members of this annotation type
195      * (member name -> associated Method object mapping).
196      */
197     public Map<String, Method> members() {
198         return members;
199     }
200
201     /**
202      * Returns the default values for this annotation type
203      * (Member name -> default value mapping).
204      */
205     public Map<String, Object> memberDefaults() {
206         return memberDefaults;
207     }
208
209     /**
210      * Returns the retention policy for this annotation type.
211      */
212     public RetentionPolicy retention() {
213         return retention;
214     }
215
216     /**
217      * Returns true if this this annotation type is inherited.
218      */
219     public boolean isInherited() {
220         return inherited;
221     }
222
223     /**
224      * For debugging.
225      */
226     public String toString() {
227         StringBuffer s = new StringBuffer("Annotation Type:" + "\n");
228         s.append("   Member types: " + memberTypes + "\n");
229         s.append("   Member defaults: " + memberDefaults + "\n");
230         s.append("   Retention policy: " + retention + "\n");
231         s.append("   Inherited: " + inherited);
232         return s.toString();
233     }
234 }