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

Thu, 10 Jun 2010 16:08:01 -0700

author
jjg
date
Thu, 10 Jun 2010 16:08:01 -0700
changeset 581
f2fdd52e4e87
parent 577
852d8bb356bc
child 713
ea92d1e275b6
permissions
-rw-r--r--

6944312: Potential rebranding issues in openjdk/langtools repository sources
Reviewed-by: darcy

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

mercurial