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

Tue, 09 Oct 2012 19:10:00 -0700

author
jjg
date
Tue, 09 Oct 2012 19:10:00 -0700
changeset 1357
c75be5bc5283
parent 1313
873ddd9f4900
child 1645
97f6839673d6
permissions
-rw-r--r--

8000663: clean up langtools imports
Reviewed-by: darcy

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

mercurial