src/share/jaxws_classes/com/sun/xml/internal/ws/model/WrapperBeanGenerator.java

Thu, 31 Aug 2017 15:18:52 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:18:52 +0800
changeset 637
9c07ef4934dd
parent 450
b0c2840e2513
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

     1 /*
     2  * Copyright (c) 1997, 2013, 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.xml.internal.ws.model;
    28 import com.sun.xml.internal.ws.model.AbstractWrapperBeanGenerator.BeanMemberFactory;
    29 import com.sun.xml.internal.bind.v2.model.annotation.AnnotationReader;
    30 import com.sun.xml.internal.bind.v2.model.annotation.RuntimeInlineAnnotationReader;
    31 import com.sun.xml.internal.bind.v2.model.nav.Navigator;
    32 import com.sun.xml.internal.ws.org.objectweb.asm.*;
    33 import static com.sun.xml.internal.ws.org.objectweb.asm.Opcodes.*;
    34 import com.sun.xml.internal.ws.org.objectweb.asm.Type;
    36 import javax.xml.bind.annotation.XmlAttachmentRef;
    37 import javax.xml.bind.annotation.XmlElement;
    38 import javax.xml.bind.annotation.XmlList;
    39 import javax.xml.bind.annotation.XmlMimeType;
    40 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
    41 import javax.xml.namespace.QName;
    42 import javax.xml.ws.Holder;
    43 import javax.xml.ws.WebServiceException;
    44 import java.lang.annotation.Annotation;
    45 import java.lang.reflect.*;
    46 import java.util.*;
    47 import java.util.logging.Level;
    48 import java.util.logging.Logger;
    50 /**
    51  * Runtime Wrapper and exception bean generator implementation.
    52  * It uses ASM to generate request, response and exception beans.
    53  *
    54  * @author Jitendra Kotamraju
    55  */
    56 public class WrapperBeanGenerator {
    58     private static final Logger LOGGER = Logger.getLogger(WrapperBeanGenerator.class.getName());
    60     private static final FieldFactory FIELD_FACTORY = new FieldFactory();
    62     private static final AbstractWrapperBeanGenerator RUNTIME_GENERATOR =
    63             new RuntimeWrapperBeanGenerator(new RuntimeInlineAnnotationReader(),
    64                     (Navigator<java.lang.reflect.Type, Class, ?, Method>) Utils.REFLECTION_NAVIGATOR, FIELD_FACTORY);
    66     private static final class RuntimeWrapperBeanGenerator extends AbstractWrapperBeanGenerator<java.lang.reflect.Type, Class, java.lang.reflect.Method, Field> {
    68         protected RuntimeWrapperBeanGenerator(AnnotationReader<java.lang.reflect.Type, Class, ?, Method> annReader, Navigator<java.lang.reflect.Type, Class, ?, Method> nav, BeanMemberFactory<java.lang.reflect.Type, Field> beanMemberFactory) {
    69             super(annReader, nav, beanMemberFactory);
    70         }
    72         @Override
    73         protected java.lang.reflect.Type getSafeType(java.lang.reflect.Type type) {
    74             return type;
    75         }
    77         @Override
    78         protected java.lang.reflect.Type getHolderValueType(java.lang.reflect.Type paramType) {
    79             if (paramType instanceof ParameterizedType) {
    80                 ParameterizedType p = (ParameterizedType)paramType;
    81                 if (p.getRawType().equals(Holder.class)) {
    82                     return p.getActualTypeArguments()[0];
    83                 }
    84             }
    85             return null;
    86         }
    88         @Override
    89         protected boolean isVoidType(java.lang.reflect.Type type) {
    90             return type == Void.TYPE;
    91         }
    93     }
    95     private static final class FieldFactory implements BeanMemberFactory<java.lang.reflect.Type, Field> {
    96         @Override
    97         public Field createWrapperBeanMember(java.lang.reflect.Type paramType,
    98                 String paramName, List<Annotation> jaxb) {
    99             return new Field(paramName, paramType, getASMType(paramType), jaxb);
   100         }
   101     }
   103     // Creates class's bytes
   104     private static byte[] createBeanImage(String className,
   105                                String rootName, String rootNS,
   106                                String typeName, String typeNS,
   107                                Collection<Field> fields) throws Exception {
   109         ClassWriter cw = new ClassWriter(0);
   110         //org.objectweb.asm.util.TraceClassVisitor cw = new org.objectweb.asm.util.TraceClassVisitor(actual, new java.io.PrintWriter(System.out));
   112         cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, replaceDotWithSlash(className), null, "java/lang/Object", null);
   114         AnnotationVisitor root = cw.visitAnnotation("Ljavax/xml/bind/annotation/XmlRootElement;", true);
   115         root.visit("name", rootName);
   116         root.visit("namespace", rootNS);
   117         root.visitEnd();
   119         AnnotationVisitor type = cw.visitAnnotation("Ljavax/xml/bind/annotation/XmlType;", true);
   120         type.visit("name", typeName);
   121         type.visit("namespace", typeNS);
   122         if (fields.size() > 1) {
   123             AnnotationVisitor propVisitor = type.visitArray("propOrder");
   124             for(Field field : fields) {
   125                 propVisitor.visit("propOrder", field.fieldName);
   126             }
   127             propVisitor.visitEnd();
   128         }
   129         type.visitEnd();
   131         for(Field field : fields) {
   132             FieldVisitor fv = cw.visitField(ACC_PUBLIC, field.fieldName, field.asmType.getDescriptor(), field.getSignature(), null);
   134             for(Annotation ann : field.jaxbAnnotations) {
   135                 if (ann instanceof XmlMimeType) {
   136                     AnnotationVisitor mime = fv.visitAnnotation("Ljavax/xml/bind/annotation/XmlMimeType;", true);
   137                     mime.visit("value", ((XmlMimeType)ann).value());
   138                     mime.visitEnd();
   139                 } else if (ann instanceof XmlJavaTypeAdapter) {
   140                     AnnotationVisitor ada = fv.visitAnnotation("Ljavax/xml/bind/annotation/adapters/XmlJavaTypeAdapter;", true);
   141                     ada.visit("value", getASMType(((XmlJavaTypeAdapter)ann).value()));
   142                     // XmlJavaTypeAdapter.type() is for package only. No need to copy.
   143                     // ada.visit("type", ((XmlJavaTypeAdapter)ann).type());
   144                     ada.visitEnd();
   145                 } else if (ann instanceof XmlAttachmentRef) {
   146                     AnnotationVisitor att = fv.visitAnnotation("Ljavax/xml/bind/annotation/XmlAttachmentRef;", true);
   147                     att.visitEnd();
   148                 } else if (ann instanceof XmlList) {
   149                     AnnotationVisitor list = fv.visitAnnotation("Ljavax/xml/bind/annotation/XmlList;", true);
   150                     list.visitEnd();
   151                 } else if (ann instanceof XmlElement) {
   152                     AnnotationVisitor elem = fv.visitAnnotation("Ljavax/xml/bind/annotation/XmlElement;", true);
   153                     XmlElement xmlElem = (XmlElement)ann;
   154                     elem.visit("name", xmlElem.name());
   155                     elem.visit("namespace", xmlElem.namespace());
   156                     if (xmlElem.nillable()) {
   157                         elem.visit("nillable", true);
   158                     }
   159                     if (xmlElem.required()) {
   160                         elem.visit("required", true);
   161                     }
   162                     elem.visitEnd();
   163                 } else {
   164                     throw new WebServiceException("Unknown JAXB annotation " + ann);
   165                 }
   166             }
   168             fv.visitEnd();
   169         }
   171         MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
   172         mv.visitCode();
   173         mv.visitVarInsn(ALOAD, 0);
   174         mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
   175         mv.visitInsn(RETURN);
   176         mv.visitMaxs(1, 1);
   177         mv.visitEnd();
   179         cw.visitEnd();
   181         if (LOGGER.isLoggable(Level.FINE)) {
   182             // Class's @XmlRootElement
   183             StringBuilder sb = new StringBuilder();
   184             sb.append("\n");
   185             sb.append("@XmlRootElement(name=").append(rootName)
   186                     .append(", namespace=").append(rootNS).append(")");
   188             // Class's @XmlType
   189             sb.append("\n");
   190             sb.append("@XmlType(name=").append(typeName)
   191                     .append(", namespace=").append(typeNS);
   192             if (fields.size() > 1) {
   193                 sb.append(", propOrder={");
   194                 for(Field field : fields) {
   195                     sb.append(" ");
   196                     sb.append(field.fieldName);
   197                 }
   198                 sb.append(" }");
   199             }
   200             sb.append(")");
   202             // class declaration
   203             sb.append("\n");
   204             sb.append("public class ").append(className).append(" {");
   206             // fields declaration
   207             for(Field field : fields) {
   208                 sb.append("\n");
   210                 // Field's other JAXB annotations
   211                 for(Annotation ann : field.jaxbAnnotations) {
   212                     sb.append("\n    ");
   214                     if (ann instanceof XmlMimeType) {
   215                         sb.append("@XmlMimeType(value=").append(((XmlMimeType)ann).value()).append(")");
   216                     } else if (ann instanceof XmlJavaTypeAdapter) {
   217                         sb.append("@XmlJavaTypeAdapter(value=").append(getASMType(((XmlJavaTypeAdapter)ann).value())).append(")");
   218                     } else if (ann instanceof XmlAttachmentRef) {
   219                         sb.append("@XmlAttachmentRef");
   220                     } else if (ann instanceof XmlList) {
   221                         sb.append("@XmlList");
   222                     } else if (ann instanceof XmlElement) {
   223                         XmlElement xmlElem = (XmlElement)ann;
   224                         sb.append("\n    ");
   225                         sb.append("@XmlElement(name=").append(xmlElem.name())
   226                                 .append(", namespace=").append(xmlElem.namespace());
   227                         if (xmlElem.nillable()) {
   228                             sb.append(", nillable=true");
   229                         }
   230                         if (xmlElem.required()) {
   231                             sb.append(", required=true");
   232                         }
   233                         sb.append(")");
   234                     } else {
   235                         throw new WebServiceException("Unknown JAXB annotation " + ann);
   236                     }
   237                 }
   239                 // Field declaration
   240                 sb.append("\n    ");
   241                 sb.append("public ");
   242                 if (field.getSignature() == null) {
   243                     sb.append(field.asmType.getDescriptor());
   244                 } else {
   245                     sb.append(field.getSignature());
   246                 }
   247                 sb.append(" ");
   248                 sb.append(field.fieldName);
   249             }
   251             sb.append("\n\n}");
   252             LOGGER.fine(sb.toString());
   253         }
   255         return cw.toByteArray();
   256     }
   258     private static String replaceDotWithSlash(String name) {
   259         return name.replace('.', '/');
   260     }
   262     static Class createRequestWrapperBean(String className, Method method, QName reqElemName, ClassLoader cl) {
   264         if (LOGGER.isLoggable(Level.FINE)) {
   265             LOGGER.log(Level.FINE, "Request Wrapper Class : {0}", className);
   266         }
   268         List<Field> requestMembers = RUNTIME_GENERATOR.collectRequestBeanMembers(
   269                 method);
   271         byte[] image;
   272         try {
   273             image = createBeanImage(className, reqElemName.getLocalPart(), reqElemName.getNamespaceURI(),
   274                 reqElemName.getLocalPart(), reqElemName.getNamespaceURI(),
   275                 requestMembers);
   276         } catch(Exception e) {
   277             throw new WebServiceException(e);
   278         }
   279 //        write(image, className);
   280         return Injector.inject(cl, className, image);
   281     }
   283     static Class createResponseWrapperBean(String className, Method method, QName resElemName, ClassLoader cl) {
   285         if (LOGGER.isLoggable(Level.FINE)) {
   286             LOGGER.log(Level.FINE, "Response Wrapper Class : {0}", className);
   287         }
   289         List<Field> responseMembers = RUNTIME_GENERATOR.collectResponseBeanMembers(method);
   291         byte[] image;
   292         try {
   293             image = createBeanImage(className, resElemName.getLocalPart(), resElemName.getNamespaceURI(),
   294                 resElemName.getLocalPart(), resElemName.getNamespaceURI(),
   295                 responseMembers);
   296         } catch(Exception e) {
   297             throw new WebServiceException(e);
   298         }
   299 //      write(image, className);
   301         return Injector.inject(cl, className, image);
   302     }
   305     private static Type getASMType(java.lang.reflect.Type t) {
   306         assert t!=null;
   308         if (t instanceof Class) {
   309             return Type.getType((Class)t);
   310         }
   312         if (t instanceof ParameterizedType) {
   313             ParameterizedType pt = (ParameterizedType)t;
   314             if (pt.getRawType() instanceof Class) {
   315                 return Type.getType((Class)pt.getRawType());
   316             }
   317         }
   318         if (t instanceof GenericArrayType) {
   319             return Type.getType(FieldSignature.vms(t));
   320         }
   322         if (t instanceof WildcardType) {
   323             return Type.getType(FieldSignature.vms(t));
   324         }
   326         if (t instanceof TypeVariable) {
   327             TypeVariable tv = (TypeVariable)t;
   328             if (tv.getBounds()[0] instanceof Class) {
   329                 return Type.getType((Class)tv.getBounds()[0]);
   330             }
   331         }
   333         throw new IllegalArgumentException("Not creating ASM Type for type = "+t);
   334     }
   337     static Class createExceptionBean(String className, Class exception, String typeNS, String elemName, String elemNS, ClassLoader cl) {
   338         return createExceptionBean(className, exception, typeNS, elemName, elemNS, cl, true);
   339     }
   341     static Class createExceptionBean(String className, Class exception, String typeNS, String elemName, String elemNS, ClassLoader cl, boolean decapitalizeExceptionBeanProperties) {
   343         Collection<Field> fields = RUNTIME_GENERATOR.collectExceptionBeanMembers(exception, decapitalizeExceptionBeanProperties);
   345         byte[] image;
   346         try {
   347             image = createBeanImage(className, elemName, elemNS,
   348                 exception.getSimpleName(), typeNS,
   349                 fields);
   350         } catch(Exception e) {
   351             throw new WebServiceException(e);
   352         }
   354         return Injector.inject(cl, className, image);
   355     }
   357     /**
   358      * Note: this class has a natural ordering that is inconsistent with equals.
   359      */
   360     private static class Field implements Comparable<Field> {
   361         private final java.lang.reflect.Type reflectType;
   362         private final Type asmType;
   363         private final String fieldName;
   364         private final List<Annotation> jaxbAnnotations;
   366         Field(String paramName, java.lang.reflect.Type paramType, Type asmType,
   367               List<Annotation> jaxbAnnotations) {
   368             this.reflectType = paramType;
   369             this.asmType = asmType;
   370             this.fieldName = paramName;
   371             this.jaxbAnnotations = jaxbAnnotations;
   372         }
   374         String getSignature() {
   375             if (reflectType instanceof Class) {
   376                 return null;
   377             }
   378             if (reflectType instanceof TypeVariable) {
   379                 return null;
   380             }
   381             return FieldSignature.vms(reflectType);
   382         }
   384         @Override
   385         public int compareTo(Field o) {
   386             return fieldName.compareTo(o.fieldName);
   387         }
   388     }
   390     static void write(byte[] b, String className) {
   391         className = className.substring(className.lastIndexOf(".")+1);
   392         try {
   393             java.io.FileOutputStream fo = new java.io.FileOutputStream(className + ".class");
   394             fo.write(b);
   395             fo.flush();
   396             fo.close();
   397         } catch (java.io.IOException e) {
   398             LOGGER.log(Level.INFO, "Error Writing class", e);
   399         }
   400     }
   402 }

mercurial