Home » openjdk-7 » com.sun.tools » javac » model » [javadoc | source]

    1   /*
    2    * Copyright (c) 2005, 2010, 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 com.sun.tools.javac.model;
   27   
   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;
   37   
   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;
   44   
   45   
   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    */
   58   
   59   public class AnnotationProxyMaker {
   60   
   61       private final Attribute.Compound anno;
   62       private final Class<? extends Annotation> annoType;
   63   
   64   
   65       private AnnotationProxyMaker(Attribute.Compound anno,
   66                                    Class<? extends Annotation> annoType) {
   67           this.anno = anno;
   68           this.annoType = annoType;
   69       }
   70   
   71   
   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       }
   80   
   81   
   82       /**
   83        * Returns a dynamic proxy for an annotation mirror.
   84        */
   85       private Annotation generateAnnotation() {
   86           return AnnotationParser.annotationForMap(annoType,
   87                                                    getAllReflectedValues());
   88       }
   89   
   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>();
   97   
   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       }
  111   
  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>();
  119   
  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       }
  135   
  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       }
  145   
  146   
  147       private class ValueVisitor implements Attribute.Visitor {
  148   
  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"
  152   
  153           ValueVisitor(MethodSymbol meth) {
  154               this.meth = meth;
  155           }
  156   
  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           }
  173   
  174   
  175           public void visitConstant(Attribute.Constant c) {
  176               value = c.getValue();
  177           }
  178   
  179           public void visitClass(Attribute.Class c) {
  180               value = new MirroredTypeExceptionProxy(c.type);
  181           }
  182   
  183           public void visitArray(Attribute.Array a) {
  184               Name elemName = ((ArrayType) a.type).elemtype.tsym.getQualifiedName();
  185   
  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());
  194   
  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           }
  219   
  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           }
  234   
  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           }
  244   
  245           public void visitError(Attribute.Error e) {
  246               value = null;       // indicates a type mismatch
  247           }
  248   
  249   
  250           /**
  251            * Sets "value" to an ExceptionProxy indicating a type mismatch.
  252            */
  253           private void typeMismatch(Method method, final Attribute attr) {
  254               class AnnotationTypeMismatchExceptionProxy extends ExceptionProxy {
  255                   static final long serialVersionUID = 269;
  256                   transient final Method method;
  257                   AnnotationTypeMismatchExceptionProxy(Method method) {
  258                       this.method = method;
  259                   }
  260                   public String toString() {
  261                       return "<error>";   // eg:  @Anno(value=<error>)
  262                   }
  263                   protected RuntimeException generateException() {
  264                       return new AnnotationTypeMismatchException(method,
  265                                   attr.type.toString());
  266                   }
  267               }
  268               value = new AnnotationTypeMismatchExceptionProxy(method);
  269           }
  270       }
  271   
  272   
  273       /**
  274        * ExceptionProxy for MirroredTypeException.
  275        * The toString, hashCode, and equals methods foward to the underlying
  276        * type.
  277        */
  278       private static final class MirroredTypeExceptionProxy extends ExceptionProxy {
  279           static final long serialVersionUID = 269;
  280   
  281           private transient TypeMirror type;
  282           private final String typeString;
  283   
  284           MirroredTypeExceptionProxy(TypeMirror t) {
  285               type = t;
  286               typeString = t.toString();
  287           }
  288   
  289           public String toString() {
  290               return typeString;
  291           }
  292   
  293           public int hashCode() {
  294               return (type != null ? type : typeString).hashCode();
  295           }
  296   
  297           public boolean equals(Object obj) {
  298               return type != null &&
  299                      obj instanceof MirroredTypeExceptionProxy &&
  300                      type.equals(((MirroredTypeExceptionProxy) obj).type);
  301           }
  302   
  303           protected RuntimeException generateException() {
  304               return new MirroredTypeException(type);
  305           }
  306   
  307           // Explicitly set all transient fields.
  308           private void readObject(ObjectInputStream s)
  309               throws IOException, ClassNotFoundException {
  310               s.defaultReadObject();
  311               type = null;
  312           }
  313       }
  314   
  315   
  316       /**
  317        * ExceptionProxy for MirroredTypesException.
  318        * The toString, hashCode, and equals methods foward to the underlying
  319        * types.
  320        */
  321       private static final class MirroredTypesExceptionProxy extends ExceptionProxy {
  322           static final long serialVersionUID = 269;
  323   
  324           private transient List<TypeMirror> types;
  325           private final String typeStrings;
  326   
  327           MirroredTypesExceptionProxy(List<TypeMirror> ts) {
  328               types = ts;
  329               typeStrings = ts.toString();
  330           }
  331   
  332           public String toString() {
  333               return typeStrings;
  334           }
  335   
  336           public int hashCode() {
  337               return (types != null ? types : typeStrings).hashCode();
  338           }
  339   
  340           public boolean equals(Object obj) {
  341               return types != null &&
  342                      obj instanceof MirroredTypesExceptionProxy &&
  343                      types.equals(
  344                         ((MirroredTypesExceptionProxy) obj).types);
  345           }
  346   
  347           protected RuntimeException generateException() {
  348               return new MirroredTypesException(types);
  349           }
  350   
  351           // Explicitly set all transient fields.
  352           private void readObject(ObjectInputStream s)
  353               throws IOException, ClassNotFoundException {
  354               s.defaultReadObject();
  355               types = null;
  356           }
  357       }
  358   }

Home » openjdk-7 » com.sun.tools » javac » model » [javadoc | source]