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