1 /* 2 * Copyright (c) 2003, 2006, 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 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 * 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<? extends Annotation> annotationClass) 80 { 81 AnnotationType result = annotationClass.getAnnotationType(); 82 if (result == null) 83 result = new AnnotationType((Class<? extends Annotation>) annotationClass); 84 85 return result; 86 } 87 88 /** 89 * Sole constructor. 90 * 91 * @param annotationClass the class object for the annotation type 92 * @throw IllegalArgumentException if the specified class object for 93 * does not represent a valid annotation type 94 */ 95 private AnnotationType(final Class<? extends Annotation> annotationClass) { 96 if (!annotationClass.isAnnotation()) 97 throw new IllegalArgumentException("Not an annotation type"); 98 99 Method[] methods = 100 AccessController.doPrivileged(new PrivilegedAction<Method[]>() { 101 public Method[] run() { 102 // Initialize memberTypes and defaultValues 103 return annotationClass.getDeclaredMethods(); 104 } 105 }); 106 107 108 for (Method method : methods) { 109 if (method.getParameterTypes().length != 0) 110 throw new IllegalArgumentException(method + " has params"); 111 String name = method.getName(); 112 Class<?> type = method.getReturnType(); 113 memberTypes.put(name, invocationHandlerReturnType(type)); 114 members.put(name, method); 115 116 Object defaultValue = method.getDefaultValue(); 117 if (defaultValue != null) 118 memberDefaults.put(name, defaultValue); 119 120 members.put(name, method); 121 } 122 123 annotationClass.setAnnotationType(this); 124 125 // Initialize retention, & inherited fields. Special treatment 126 // of the corresponding annotation types breaks infinite recursion. 127 if (annotationClass != Retention.class && 128 annotationClass != Inherited.class) { 129 Retention ret = annotationClass.getAnnotation(Retention.class); 130 retention = (ret == null ? RetentionPolicy.CLASS : ret.value()); 131 inherited = annotationClass.isAnnotationPresent(Inherited.class); 132 } 133 } 134 135 /** 136 * Returns the type that must be returned by the invocation handler 137 * of a dynamic proxy in order to have the dynamic proxy return 138 * the specified type (which is assumed to be a legal member type 139 * for an annotation). 140 */ 141 public static Class<?> invocationHandlerReturnType(Class<?> type) { 142 // Translate primitives to wrappers 143 if (type == byte.class) 144 return Byte.class; 145 if (type == char.class) 146 return Character.class; 147 if (type == double.class) 148 return Double.class; 149 if (type == float.class) 150 return Float.class; 151 if (type == int.class) 152 return Integer.class; 153 if (type == long.class) 154 return Long.class; 155 if (type == short.class) 156 return Short.class; 157 if (type == boolean.class) 158 return Boolean.class; 159 160 // Otherwise, just return declared type 161 return type; 162 } 163 164 /** 165 * Returns member types for this annotation type 166 * (member name -> type mapping). 167 */ 168 public Map<String, Class<?>> memberTypes() { 169 return memberTypes; 170 } 171 172 /** 173 * Returns members of this annotation type 174 * (member name -> associated Method object mapping). 175 */ 176 public Map<String, Method> members() { 177 return members; 178 } 179 180 /** 181 * Returns the default values for this annotation type 182 * (Member name -> default value mapping). 183 */ 184 public Map<String, Object> memberDefaults() { 185 return memberDefaults; 186 } 187 188 /** 189 * Returns the retention policy for this annotation type. 190 */ 191 public RetentionPolicy retention() { 192 return retention; 193 } 194 195 /** 196 * Returns true if this this annotation type is inherited. 197 */ 198 public boolean isInherited() { 199 return inherited; 200 } 201 202 /** 203 * For debugging. 204 */ 205 public String toString() { 206 StringBuffer s = new StringBuffer("Annotation Type:" + "\n"); 207 s.append(" Member types: " + memberTypes + "\n"); 208 s.append(" Member defaults: " + memberDefaults + "\n"); 209 s.append(" Retention policy: " + retention + "\n"); 210 s.append(" Inherited: " + inherited); 211 return s.toString(); 212 } 213 } 214