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      * 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 = sun.misc.SharedSecrets.getJavaLangAccess().
  82             getAnnotationType(annotationClass);
  83         if (result == null)
  84             result = new AnnotationType((Class<? extends Annotation>) 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<? extends Annotation> 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 }