Home | History | Annotate | Download | only in annotation
      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