src/share/jaxws_classes/com/sun/codemodel/internal/TypedAnnotationWriter.java

Thu, 12 Oct 2017 19:44:07 +0800

author
aoqi
date
Thu, 12 Oct 2017 19:44:07 +0800
changeset 760
e530533619ec
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

     1 /*
     2  * Copyright (c) 1997, 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  */
    26 package com.sun.codemodel.internal;
    28 import java.lang.reflect.InvocationHandler;
    29 import java.lang.reflect.Method;
    30 import java.lang.reflect.Proxy;
    31 import java.lang.reflect.Type;
    32 import java.lang.reflect.ParameterizedType;
    33 import java.lang.reflect.InvocationTargetException;
    34 import java.lang.annotation.Annotation;
    35 import java.util.Map;
    36 import java.util.HashMap;
    38 /**
    39  * Dynamically implements the typed annotation writer interfaces.
    40  *
    41  * @author Kohsuke Kawaguchi
    42  */
    43 class TypedAnnotationWriter<A extends Annotation,W extends JAnnotationWriter<A>>
    44     implements InvocationHandler, JAnnotationWriter<A> {
    45     /**
    46      * This is what we are writing to.
    47      */
    48     private final JAnnotationUse use;
    50     /**
    51      * The annotation that we are writing.
    52      */
    53     private final Class<A> annotation;
    55     /**
    56      * The type of the writer.
    57      */
    58     private final Class<W> writerType;
    60     /**
    61      * Keeps track of writers for array members.
    62      * Lazily created.
    63      */
    64     private Map<String,JAnnotationArrayMember> arrays;
    66     public TypedAnnotationWriter(Class<A> annotation, Class<W> writer, JAnnotationUse use) {
    67         this.annotation = annotation;
    68         this.writerType = writer;
    69         this.use = use;
    70     }
    72     public JAnnotationUse getAnnotationUse() {
    73         return use;
    74     }
    76     public Class<A> getAnnotationType() {
    77         return annotation;
    78     }
    80     @SuppressWarnings("unchecked")
    81         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    83         if(method.getDeclaringClass()==JAnnotationWriter.class) {
    84             try {
    85                 return method.invoke(this,args);
    86             } catch (InvocationTargetException e) {
    87                 throw e.getTargetException();
    88             }
    89         }
    91         String name = method.getName();
    92         Object arg=null;
    93         if(args!=null && args.length>0)
    94             arg = args[0];
    96         // check how it's defined on the annotation
    97         Method m = annotation.getDeclaredMethod(name);
    98         Class<?> rt = m.getReturnType();
   100         // array value
   101         if(rt.isArray()) {
   102             return addArrayValue(proxy,name,rt.getComponentType(),method.getReturnType(),arg);
   103         }
   105         // sub annotation
   106         if(Annotation.class.isAssignableFrom(rt)) {
   107             Class<? extends Annotation> r = (Class<? extends Annotation>)rt;
   108             return new TypedAnnotationWriter(
   109                 r,method.getReturnType(),use.annotationParam(name,r)).createProxy();
   110         }
   112         // scalar value
   114         if(arg instanceof JType) {
   115             JType targ = (JType) arg;
   116             checkType(Class.class,rt);
   117             if(m.getDefaultValue()!=null) {
   118                 // check the default
   119                 if(targ.equals(targ.owner().ref((Class)m.getDefaultValue())))
   120                     return proxy;   // defaulted
   121             }
   122             use.param(name,targ);
   123             return proxy;
   124         }
   126         // other Java built-in types
   127         checkType(arg.getClass(),rt);
   128         if(m.getDefaultValue()!=null && m.getDefaultValue().equals(arg))
   129             // defaulted. no need to write out.
   130             return proxy;
   132         if(arg instanceof String) {
   133             use.param(name,(String)arg);
   134             return proxy;
   135         }
   136         if(arg instanceof Boolean) {
   137             use.param(name,(Boolean)arg);
   138             return proxy;
   139         }
   140         if(arg instanceof Integer) {
   141             use.param(name,(Integer)arg);
   142             return proxy;
   143         }
   144         if(arg instanceof Class) {
   145             use.param(name,(Class)arg);
   146             return proxy;
   147         }
   148         if(arg instanceof Enum) {
   149             use.param(name,(Enum)arg);
   150             return proxy;
   151         }
   153         throw new IllegalArgumentException("Unable to handle this method call "+method.toString());
   154     }
   156     @SuppressWarnings("unchecked")
   157         private Object addArrayValue(Object proxy,String name, Class itemType, Class expectedReturnType, Object arg) {
   158         if(arrays==null)
   159             arrays = new HashMap<String,JAnnotationArrayMember>();
   160         JAnnotationArrayMember m = arrays.get(name);
   161         if(m==null) {
   162             m = use.paramArray(name);
   163             arrays.put(name,m);
   164         }
   166         // sub annotation
   167         if(Annotation.class.isAssignableFrom(itemType)) {
   168             Class<? extends Annotation> r = (Class<? extends Annotation>)itemType;
   169             if(!JAnnotationWriter.class.isAssignableFrom(expectedReturnType))
   170                 throw new IllegalArgumentException("Unexpected return type "+expectedReturnType);
   171             return new TypedAnnotationWriter(r,expectedReturnType,m.annotate(r)).createProxy();
   172         }
   174         // primitive
   175         if(arg instanceof JType) {
   176             checkType(Class.class,itemType);
   177             m.param((JType)arg);
   178             return proxy;
   179         }
   180         checkType(arg.getClass(),itemType);
   181         if(arg instanceof String) {
   182             m.param((String)arg);
   183             return proxy;
   184         }
   185         if(arg instanceof Boolean) {
   186             m.param((Boolean)arg);
   187             return proxy;
   188         }
   189         if(arg instanceof Integer) {
   190             m.param((Integer)arg);
   191             return proxy;
   192         }
   193         if(arg instanceof Class) {
   194             m.param((Class)arg);
   195             return proxy;
   196         }
   197         // TODO: enum constant. how should we handle it?
   199         throw new IllegalArgumentException("Unable to handle this method call ");
   200     }
   203     /**
   204      * Check if the type of the argument matches our expectation.
   205      * If not, report an error.
   206      */
   207     private void checkType(Class<?> actual, Class<?> expected) {
   208         if(expected==actual || expected.isAssignableFrom(actual))
   209             return; // no problem
   211         if( expected==JCodeModel.boxToPrimitive.get(actual) )
   212             return; // no problem
   214         throw new IllegalArgumentException("Expected "+expected+" but found "+actual);
   215     }
   217     /**
   218      * Creates a proxy and returns it.
   219      */
   220     @SuppressWarnings("unchecked")
   221         private W createProxy() {
   222         return (W)Proxy.newProxyInstance(
   223             SecureLoader.getClassClassLoader(writerType),new Class[]{writerType},this);
   224     }
   226     /**
   227      * Creates a new typed annotation writer.
   228      */
   229     @SuppressWarnings("unchecked")
   230         static <W extends JAnnotationWriter<?>> W create(Class<W> w, JAnnotatable annotatable) {
   231         Class<? extends Annotation> a = findAnnotationType(w);
   232         return (W)new TypedAnnotationWriter(a,w,annotatable.annotate(a)).createProxy();
   233     }
   235     private static Class<? extends Annotation> findAnnotationType(Class<?> clazz) {
   236         for( Type t : clazz.getGenericInterfaces()) {
   237             if(t instanceof ParameterizedType) {
   238                 ParameterizedType p = (ParameterizedType) t;
   239                 if(p.getRawType()==JAnnotationWriter.class)
   240                     return (Class<? extends Annotation>)p.getActualTypeArguments()[0];
   241             }
   242             if(t instanceof Class<?>) {
   243                 // recursive search
   244                 Class<? extends Annotation> r = findAnnotationType((Class<?>)t);
   245                 if(r!=null)     return r;
   246             }
   247         }
   248         return null;
   249     }
   250 }

mercurial