src/share/classes/com/sun/tools/javac/model/AnnotationProxyMaker.java

Thu, 02 Oct 2008 19:58:40 -0700

author
xdono
date
Thu, 02 Oct 2008 19:58:40 -0700
changeset 117
24a47c3062fe
parent 113
eff38cc97183
child 184
905e151a185a
permissions
-rw-r--r--

6754988: Update copyright year
Summary: Update for files that have been modified starting July 2008
Reviewed-by: ohair, tbell

     1 /*
     2  * Copyright 2005-2008 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  */
    26 package com.sun.tools.javac.model;
    28 import com.sun.tools.javac.util.*;
    29 import java.lang.annotation.*;
    30 import java.lang.reflect.Array;
    31 import java.lang.reflect.Method;
    32 import java.util.LinkedHashMap;
    33 import java.util.Map;
    34 import sun.reflect.annotation.*;
    36 import javax.lang.model.type.TypeMirror;
    37 import javax.lang.model.type.MirroredTypeException;
    38 import javax.lang.model.type.MirroredTypesException;
    39 import com.sun.tools.javac.code.*;
    40 import com.sun.tools.javac.code.Symbol.*;
    41 import com.sun.tools.javac.code.Type.ArrayType;
    44 /**
    45  * A generator of dynamic proxy implementations of
    46  * java.lang.annotation.Annotation.
    47  *
    48  * <p> The "dynamic proxy return form" of an annotation element value is
    49  * the form used by sun.reflect.annotation.AnnotationInvocationHandler.
    50  *
    51  * <p><b>This is NOT part of any API supported by Sun Microsystems.  If
    52  * you write code that depends on this, you do so at your own risk.
    53  * This code and its internal interfaces are subject to change or
    54  * deletion without notice.</b>
    55  */
    57 public class AnnotationProxyMaker {
    59     private final Attribute.Compound anno;
    60     private final Class<? extends Annotation> annoType;
    63     private AnnotationProxyMaker(Attribute.Compound anno,
    64                                  Class<? extends Annotation> annoType) {
    65         this.anno = anno;
    66         this.annoType = annoType;
    67     }
    70     /**
    71      * Returns a dynamic proxy for an annotation mirror.
    72      */
    73     public static <A extends Annotation> A generateAnnotation(
    74             Attribute.Compound anno, Class<A> annoType) {
    75         AnnotationProxyMaker apm = new AnnotationProxyMaker(anno, annoType);
    76         return annoType.cast(apm.generateAnnotation());
    77     }
    80     /**
    81      * Returns a dynamic proxy for an annotation mirror.
    82      */
    83     private Annotation generateAnnotation() {
    84         return AnnotationParser.annotationForMap(annoType,
    85                                                  getAllReflectedValues());
    86     }
    88     /**
    89      * Returns a map from element names to their values in "dynamic
    90      * proxy return form".  Includes all elements, whether explicit or
    91      * defaulted.
    92      */
    93     private Map<String, Object> getAllReflectedValues() {
    94         Map<String, Object> res = new LinkedHashMap<String, Object>();
    96         for (Map.Entry<MethodSymbol, Attribute> entry :
    97                                                   getAllValues().entrySet()) {
    98             MethodSymbol meth = entry.getKey();
    99             Object value = generateValue(meth, entry.getValue());
   100             if (value != null) {
   101                 res.put(meth.name.toString(), value);
   102             } else {
   103                 // Ignore this element.  May (properly) lead to
   104                 // IncompleteAnnotationException somewhere down the line.
   105             }
   106         }
   107         return res;
   108     }
   110     /**
   111      * Returns a map from element symbols to their values.
   112      * Includes all elements, whether explicit or defaulted.
   113      */
   114     private Map<MethodSymbol, Attribute> getAllValues() {
   115         Map<MethodSymbol, Attribute> res =
   116             new LinkedHashMap<MethodSymbol, Attribute>();
   118         // First find the default values.
   119         ClassSymbol sym = (ClassSymbol) anno.type.tsym;
   120         for (Scope.Entry e = sym.members().elems; e != null; e = e.sibling) {
   121             if (e.sym.kind == Kinds.MTH) {
   122                 MethodSymbol m = (MethodSymbol) e.sym;
   123                 Attribute def = m.getDefaultValue();
   124                 if (def != null)
   125                     res.put(m, def);
   126             }
   127         }
   128         // Next find the explicit values, possibly overriding defaults.
   129         for (Pair<MethodSymbol, Attribute> p : anno.values)
   130             res.put(p.fst, p.snd);
   131         return res;
   132     }
   134     /**
   135      * Converts an element value to its "dynamic proxy return form".
   136      * Returns an exception proxy on some errors, but may return null if
   137      * a useful exception cannot or should not be generated at this point.
   138      */
   139     private Object generateValue(MethodSymbol meth, Attribute attr) {
   140         ValueVisitor vv = new ValueVisitor(meth);
   141         return vv.getValue(attr);
   142     }
   145     private class ValueVisitor implements Attribute.Visitor {
   147         private MethodSymbol meth;      // annotation element being visited
   148         private Class<?> returnClass;   // return type of annotation element
   149         private Object value;           // value in "dynamic proxy return form"
   151         ValueVisitor(MethodSymbol meth) {
   152             this.meth = meth;
   153         }
   155         Object getValue(Attribute attr) {
   156             Method method;              // runtime method of annotation element
   157             try {
   158                 method = annoType.getMethod(meth.name.toString());
   159             } catch (NoSuchMethodException e) {
   160                 return null;
   161             }
   162             returnClass = method.getReturnType();
   163             attr.accept(this);
   164             if (!(value instanceof ExceptionProxy) &&
   165                 !AnnotationType.invocationHandlerReturnType(returnClass)
   166                                                         .isInstance(value)) {
   167                 typeMismatch(method, attr);
   168             }
   169             return value;
   170         }
   173         public void visitConstant(Attribute.Constant c) {
   174             value = c.getValue();
   175         }
   177         public void visitClass(Attribute.Class c) {
   178             value = new MirroredTypeExceptionProxy(c.type);
   179         }
   181         public void visitArray(Attribute.Array a) {
   182             Name elemName = ((ArrayType) a.type).elemtype.tsym.name;
   184             if (elemName == elemName.table.names.java_lang_Class) {   // Class[]
   185                 // Construct a proxy for a MirroredTypesException
   186                 List<TypeMirror> elems = List.nil();
   187                 for (Attribute value : a.values) {
   188                     Type elem = ((Attribute.Class) value).type;
   189                     elems.add(elem);
   190                 }
   191                 value = new MirroredTypesExceptionProxy(elems);
   193             } else {
   194                 int len = a.values.length;
   195                 Class<?> returnClassSaved = returnClass;
   196                 returnClass = returnClass.getComponentType();
   197                 try {
   198                     Object res = Array.newInstance(returnClass, len);
   199                     for (int i = 0; i < len; i++) {
   200                         a.values[i].accept(this);
   201                         if (value == null || value instanceof ExceptionProxy) {
   202                             return;
   203                         }
   204                         try {
   205                             Array.set(res, i, value);
   206                         } catch (IllegalArgumentException e) {
   207                             value = null;       // indicates a type mismatch
   208                             return;
   209                         }
   210                     }
   211                     value = res;
   212                 } finally {
   213                     returnClass = returnClassSaved;
   214                 }
   215             }
   216         }
   218         @SuppressWarnings("unchecked")
   219         public void visitEnum(Attribute.Enum e) {
   220             if (returnClass.isEnum()) {
   221                 String constName = e.value.toString();
   222                 try {
   223                     value = Enum.valueOf((Class) returnClass, constName);
   224                 } catch (IllegalArgumentException ex) {
   225                     value = new EnumConstantNotPresentExceptionProxy(
   226                                         (Class) returnClass, constName);
   227                 }
   228             } else {
   229                 value = null;   // indicates a type mismatch
   230             }
   231         }
   233         public void visitCompound(Attribute.Compound c) {
   234             try {
   235                 Class<? extends Annotation> nested =
   236                     returnClass.asSubclass(Annotation.class);
   237                 value = generateAnnotation(c, nested);
   238             } catch (ClassCastException ex) {
   239                 value = null;   // indicates a type mismatch
   240             }
   241         }
   243         public void visitError(Attribute.Error e) {
   244             value = null;       // indicates a type mismatch
   245         }
   248         /**
   249          * Sets "value" to an ExceptionProxy indicating a type mismatch.
   250          */
   251         private void typeMismatch(final Method method, final Attribute attr) {
   252             value = new ExceptionProxy() {
   253                 static final long serialVersionUID = 269;
   254                 public String toString() {
   255                     return "<error>";   // eg:  @Anno(value=<error>)
   256                 }
   257                 protected RuntimeException generateException() {
   258                     return new AnnotationTypeMismatchException(method,
   259                                 attr.type.toString());
   260                 }
   261             };
   262         }
   263     }
   266     /**
   267      * ExceptionProxy for MirroredTypeException.
   268      * The toString, hashCode, and equals methods foward to the underlying
   269      * type.
   270      */
   271     private static class MirroredTypeExceptionProxy extends ExceptionProxy {
   272         static final long serialVersionUID = 269;
   274         private transient final TypeMirror type;
   275         private final String typeString;
   277         MirroredTypeExceptionProxy(TypeMirror t) {
   278             type = t;
   279             typeString = t.toString();
   280         }
   282         public String toString() {
   283             return typeString;
   284         }
   286         public int hashCode() {
   287             return (type != null ? type : typeString).hashCode();
   288         }
   290         public boolean equals(Object obj) {
   291             return type != null &&
   292                    obj instanceof MirroredTypeExceptionProxy &&
   293                    type.equals(((MirroredTypeExceptionProxy) obj).type);
   294         }
   296         protected RuntimeException generateException() {
   297             return new MirroredTypeException(type);
   298         }
   299     }
   302     /**
   303      * ExceptionProxy for MirroredTypesException.
   304      * The toString, hashCode, and equals methods foward to the underlying
   305      * types.
   306      */
   307     private static class MirroredTypesExceptionProxy extends ExceptionProxy {
   308         static final long serialVersionUID = 269;
   310         private transient final List<TypeMirror> types;
   311         private final String typeStrings;
   313         MirroredTypesExceptionProxy(List<TypeMirror> ts) {
   314             types = ts;
   315             typeStrings = ts.toString();
   316         }
   318         public String toString() {
   319             return typeStrings;
   320         }
   322         public int hashCode() {
   323             return (types != null ? types : typeStrings).hashCode();
   324         }
   326         public boolean equals(Object obj) {
   327             return types != null &&
   328                    obj instanceof MirroredTypesExceptionProxy &&
   329                    types.equals(
   330                       ((MirroredTypesExceptionProxy) obj).types);
   331         }
   333         protected RuntimeException generateException() {
   334             return new MirroredTypesException(types);
   335         }
   336     }
   337 }

mercurial