diff options
Diffstat (limited to '')
-rw-r--r-- | branches/sca-java-1.x/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/BaseBeanGenerator.java | 539 |
1 files changed, 539 insertions, 0 deletions
diff --git a/branches/sca-java-1.x/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/BaseBeanGenerator.java b/branches/sca-java-1.x/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/BaseBeanGenerator.java new file mode 100644 index 0000000000..4cf56fed0c --- /dev/null +++ b/branches/sca-java-1.x/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/BaseBeanGenerator.java @@ -0,0 +1,539 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.interfacedef.java.jaxws; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.WeakHashMap; + +import javax.xml.bind.annotation.XmlAttachmentRef; +import javax.xml.bind.annotation.XmlList; +import javax.xml.bind.annotation.XmlMimeType; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; +import javax.xml.ws.Holder; + +import org.apache.tuscany.sca.databinding.jaxb.XMLAdapterExtensionPoint; +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +public abstract class BaseBeanGenerator implements Opcodes { + private static final Map<String, String> COLLECTION_CLASSES = new HashMap<String, String>(); + static { + COLLECTION_CLASSES.put("Ljava/util/Collection;", "java/util/ArrayList"); + COLLECTION_CLASSES.put("Ljava/util/List;", "java/util/ArrayList"); + COLLECTION_CLASSES.put("Ljava/util/Set;", "java/util/HashSet"); + COLLECTION_CLASSES.put("Ljava/util/Queue;", "java/util/LinkedList"); + } + private final static Class[] KNOWN_JAXB_ANNOTATIONS = + {XmlAttachmentRef.class, XmlMimeType.class, XmlJavaTypeAdapter.class, XmlList.class}; + private static final Map<String, String> JAVA_KEYWORDS = new HashMap<String, String>(); + + static { + JAVA_KEYWORDS.put("abstract", "_abstract"); + JAVA_KEYWORDS.put("assert", "_assert"); + JAVA_KEYWORDS.put("boolean", "_boolean"); + JAVA_KEYWORDS.put("break", "_break"); + JAVA_KEYWORDS.put("byte", "_byte"); + JAVA_KEYWORDS.put("case", "_case"); + JAVA_KEYWORDS.put("catch", "_catch"); + JAVA_KEYWORDS.put("char", "_char"); + JAVA_KEYWORDS.put("class", "_class"); + JAVA_KEYWORDS.put("const", "_const"); + JAVA_KEYWORDS.put("continue", "_continue"); + JAVA_KEYWORDS.put("default", "_default"); + JAVA_KEYWORDS.put("do", "_do"); + JAVA_KEYWORDS.put("double", "_double"); + JAVA_KEYWORDS.put("else", "_else"); + JAVA_KEYWORDS.put("extends", "_extends"); + JAVA_KEYWORDS.put("false", "_false"); + JAVA_KEYWORDS.put("final", "_final"); + JAVA_KEYWORDS.put("finally", "_finally"); + JAVA_KEYWORDS.put("float", "_float"); + JAVA_KEYWORDS.put("for", "_for"); + JAVA_KEYWORDS.put("goto", "_goto"); + JAVA_KEYWORDS.put("if", "_if"); + JAVA_KEYWORDS.put("implements", "_implements"); + JAVA_KEYWORDS.put("import", "_import"); + JAVA_KEYWORDS.put("instanceof", "_instanceof"); + JAVA_KEYWORDS.put("int", "_int"); + JAVA_KEYWORDS.put("interface", "_interface"); + JAVA_KEYWORDS.put("long", "_long"); + JAVA_KEYWORDS.put("native", "_native"); + JAVA_KEYWORDS.put("new", "_new"); + JAVA_KEYWORDS.put("null", "_null"); + JAVA_KEYWORDS.put("package", "_package"); + JAVA_KEYWORDS.put("private", "_private"); + JAVA_KEYWORDS.put("protected", "_protected"); + JAVA_KEYWORDS.put("public", "_public"); + JAVA_KEYWORDS.put("return", "_return"); + JAVA_KEYWORDS.put("short", "_short"); + JAVA_KEYWORDS.put("static", "_static"); + JAVA_KEYWORDS.put("strictfp", "_strictfp"); + JAVA_KEYWORDS.put("super", "_super"); + JAVA_KEYWORDS.put("switch", "_switch"); + JAVA_KEYWORDS.put("synchronized", "_synchronized"); + JAVA_KEYWORDS.put("this", "_this"); + JAVA_KEYWORDS.put("throw", "_throw"); + JAVA_KEYWORDS.put("throws", "_throws"); + JAVA_KEYWORDS.put("transient", "_transient"); + JAVA_KEYWORDS.put("true", "_true"); + JAVA_KEYWORDS.put("try", "_try"); + JAVA_KEYWORDS.put("void", "_void"); + JAVA_KEYWORDS.put("volatile", "_volatile"); + JAVA_KEYWORDS.put("while", "_while"); + JAVA_KEYWORDS.put("enum", "_enum"); + } + + protected static final Map<Object, Class<?>> generatedClasses = + Collections.synchronizedMap(new WeakHashMap<Object, Class<?>>()); + + protected XMLAdapterExtensionPoint xmlAdapters; + + public byte[] defineClass(ClassWriter cw, + String classDescriptor, + String classSignature, + String namespace, + String name, + BeanProperty[] properties) { + // Declare the class + declareClass(cw, classDescriptor); + + // Compute the propOrder + String[] propOrder = null; + if (properties != null && properties.length > 0) { + int size = properties.length; + propOrder = new String[size]; + for (int i = 0; i < size; i++) { + propOrder[i] = getFieldName(properties[i].getName()); + } + } + // Annotate the class + annotateClass(cw, name, namespace, propOrder); + + // Decalre the default constructor + declareConstructor(cw, classSignature); + if (properties != null) { + for (BeanProperty p : properties) { + boolean isElement = p.isElement() && (!Map.class.isAssignableFrom(p.getType())); + String xmlAdapterClassSignature = null; + if (xmlAdapters != null) { + Class<?> adapterClass = xmlAdapters.getAdapter(p.getType()); + if (adapterClass != null) { + xmlAdapterClassSignature = CodeGenerationHelper.getSignature(adapterClass); + } + } + declareProperty(cw, classDescriptor, classSignature, p.getName(), p.getSignature(), p + .getGenericSignature(), isElement, p.isNillable(), xmlAdapterClassSignature, p.getJaxbAnnotaions()); + } + } + + // Close the generation + cw.visitEnd(); + return cw.toByteArray(); + } + + protected static boolean isHolder(java.lang.reflect.Type type) { + if (type instanceof ParameterizedType) { + Class<?> cls = CodeGenerationHelper.getErasure(type); + return cls == Holder.class; + } + return false; + } + + protected static java.lang.reflect.Type getHolderValueType(java.lang.reflect.Type paramType) { + if (paramType instanceof ParameterizedType) { + ParameterizedType p = (ParameterizedType)paramType; + Class<?> cls = CodeGenerationHelper.getErasure(p); + if (cls == Holder.class) { + return p.getActualTypeArguments()[0]; + } + } + return paramType; + } + + protected void declareProperty(ClassWriter cw, + String classDescriptor, + String classSignature, + String propName, + String propClassSignature, + String propTypeSignature, + boolean isElement, + boolean isNillable, + String xmlAdapterClassSignature, + List<Annotation> jaxbAnnotations) { + if (propClassSignature.equals(propTypeSignature)) { + propTypeSignature = null; + } + declareField(cw, + propName, + propClassSignature, + propTypeSignature, + isElement, + isNillable, + xmlAdapterClassSignature, + jaxbAnnotations); + decalreGetter(cw, classDescriptor, classSignature, propName, propClassSignature, propTypeSignature); + declareSetter(cw, classDescriptor, classSignature, propName, propClassSignature, propTypeSignature); + } + + protected String getFieldName(String propName) { + String name = JAVA_KEYWORDS.get(propName); + return name != null ? name : propName; + } + + protected void declareField(ClassWriter cw, + String propName, + String propClassSignature, + String propTypeSignature, + boolean isElement, + boolean isNillable, + String xmlAdapterClassSignature, + List<Annotation> jaxbAnnotations) { + FieldVisitor fv; + AnnotationVisitor av0; + fv = cw.visitField(ACC_PROTECTED, getFieldName(propName), propClassSignature, propTypeSignature, null); + + // For Map property, we cannot have the XmlElement annotation + if (isElement) { + av0 = fv.visitAnnotation("Ljavax/xml/bind/annotation/XmlElement;", true); + av0.visit("name", propName); + av0.visit("namespace", ""); + if (isNillable) { + av0.visit("nillable", Boolean.TRUE); + } + // FIXME: + // av0.visit("required", Boolean.FALSE); + av0.visitEnd(); + } + + if (xmlAdapterClassSignature != null) { + av0 = fv.visitAnnotation("Ljavax/xml/bind/annotation/adapters/XmlJavaTypeAdapter;", true); + av0.visit("value", org.objectweb.asm.Type.getType(xmlAdapterClassSignature)); + av0.visitEnd(); + } + + for (Annotation ann : jaxbAnnotations) { + if (ann instanceof XmlMimeType) { + AnnotationVisitor mime = fv.visitAnnotation("Ljavax/xml/bind/annotation/XmlMimeType;", true); + mime.visit("value", ((XmlMimeType)ann).value()); + mime.visitEnd(); + } else if (ann instanceof XmlJavaTypeAdapter) { + AnnotationVisitor ada = fv.visitAnnotation("Ljavax/xml/bind/annotation/XmlJavaTypeAdapter;", true); + ada.visit("value", ((XmlJavaTypeAdapter)ann).value()); + ada.visit("type", ((XmlJavaTypeAdapter)ann).type()); + ada.visitEnd(); + } else if (ann instanceof XmlAttachmentRef) { + AnnotationVisitor att = fv.visitAnnotation("Ljavax/xml/bind/annotation/XmlAttachmentRef;", true); + att.visitEnd(); + } else if (ann instanceof XmlList) { + AnnotationVisitor list = fv.visitAnnotation("Ljavax/xml/bind/annotation/XmlList;", true); + list.visitEnd(); + } + } + + fv.visitEnd(); + } + + protected void declareSetter(ClassWriter cw, + String classDescriptor, + String classSignature, + String propName, + String propClassSignature, + String propTypeSignature) { + if ("Ljava/util/List;".equals(propClassSignature)) { + return; + } + MethodVisitor mv = + cw.visitMethod(ACC_PUBLIC, + "set" + capitalize(propName), + "(" + propClassSignature + ")V", + propTypeSignature == null ? null : "(" + propTypeSignature + ")V", + null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + // mv.visitLineNumber(57, l0); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(CodeGenerationHelper.getLoadOPCode(propClassSignature), 1); + mv.visitFieldInsn(PUTFIELD, classDescriptor, getFieldName(propName), propClassSignature); + Label l1 = new Label(); + mv.visitLabel(l1); + // mv.visitLineNumber(58, l1); + mv.visitInsn(RETURN); + Label l2 = new Label(); + mv.visitLabel(l2); + mv.visitLocalVariable("this", classSignature, null, l0, l2, 0); + mv.visitLocalVariable(getFieldName(propName), propClassSignature, propTypeSignature, l0, l2, 1); + mv.visitMaxs(3, 3); + mv.visitEnd(); + + } + + protected void decalreGetter(ClassWriter cw, + String classDescriptor, + String classSignature, + String propName, + String propClassSignature, + String propTypeSignature) { + String collectionImplClass = COLLECTION_CLASSES.get(propClassSignature); + if (collectionImplClass != null) { + decalreCollectionGetter(cw, + classDescriptor, + classSignature, + propName, + propClassSignature, + propTypeSignature, + collectionImplClass); + return; + } + + String getterName = ("Z".equals(propClassSignature) ? "is" : "get") + capitalize(propName); + MethodVisitor mv = + cw.visitMethod(ACC_PUBLIC, getterName, "()" + propClassSignature, propTypeSignature == null ? null + : "()" + propTypeSignature, null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + // mv.visitLineNumber(48, l0); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, classDescriptor, getFieldName(propName), propClassSignature); + mv.visitInsn(CodeGenerationHelper.getReturnOPCode(propClassSignature)); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitLocalVariable("this", classSignature, null, l0, l1, 0); + mv.visitMaxs(2, 1); + mv.visitEnd(); + } + + protected void decalreCollectionGetter(ClassWriter cw, + String classDescriptor, + String classSignature, + String propName, + String propClassSignature, + String propTypeSignature, + String collectionImplClass) { + String getterName = "get" + capitalize(propName); + String fieldName = getFieldName(propName); + MethodVisitor mv = + cw.visitMethod(ACC_PUBLIC, getterName, "()" + propClassSignature, propTypeSignature == null ? null + : "()" + propTypeSignature, null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + mv.visitLineNumber(63, l0); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, classDescriptor, fieldName, propClassSignature); + Label l1 = new Label(); + mv.visitJumpInsn(IFNONNULL, l1); + Label l2 = new Label(); + mv.visitLabel(l2); + mv.visitLineNumber(64, l2); + mv.visitVarInsn(ALOAD, 0); + mv.visitTypeInsn(NEW, collectionImplClass); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, collectionImplClass, "<init>", "()V"); + mv.visitFieldInsn(PUTFIELD, classDescriptor, fieldName, propClassSignature); + mv.visitLabel(l1); + mv.visitLineNumber(66, l1); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, classDescriptor, fieldName, propClassSignature); + mv.visitInsn(ARETURN); + Label l3 = new Label(); + mv.visitLabel(l3); + mv.visitLocalVariable("this", classSignature, null, l0, l3, 0); + mv.visitMaxs(3, 1); + mv.visitEnd(); + } + + protected static String capitalize(String name) { + if (name == null || name.length() == 0) { + return name; + } else { + return Character.toUpperCase(name.charAt(0)) + name.substring(1); + } + } + + protected void declareConstructor(ClassWriter cw, String classSignature) { + MethodVisitor mv; + mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); + mv.visitCode(); + Label l0 = new Label(); + mv.visitLabel(l0); + // mv.visitLineNumber(37, l0); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); + mv.visitInsn(RETURN); + Label l1 = new Label(); + mv.visitLabel(l1); + mv.visitLocalVariable("this", classSignature, null, l0, l1, 0); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + + protected void declareClass(ClassWriter cw, String classDescriptor) { + cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, classDescriptor, null, "java/lang/Object", null); + } + + protected void annotateClass(ClassWriter cw, String name, String namespace, String[] propOrder) { + AnnotationVisitor av0; + // @XmlRootElement + av0 = cw.visitAnnotation("Ljavax/xml/bind/annotation/XmlRootElement;", true); + av0.visit("name", name); + av0.visit("namespace", namespace); + av0.visitEnd(); + // @XmlAccessorType + av0 = cw.visitAnnotation("Ljavax/xml/bind/annotation/XmlAccessorType;", true); + av0.visitEnum("value", "Ljavax/xml/bind/annotation/XmlAccessType;", "FIELD"); + av0.visitEnd(); + // @XmlType + av0 = cw.visitAnnotation("Ljavax/xml/bind/annotation/XmlType;", true); + av0.visit("name", name); + av0.visit("namespace", namespace); + if (propOrder != null) { + AnnotationVisitor pv = av0.visitArray("propOrder"); + for (String p : propOrder) { + pv.visit(null, p); + } + pv.visitEnd(); + } + av0.visitEnd(); + } + + public Class<?> generate(String classDescriptor, + String classSignature, + String namespace, + String name, + BeanProperty[] properties, + GeneratedClassLoader classLoader) { + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); + byte[] byteCode = defineClass(cw, classDescriptor, classSignature, namespace, name, properties); + String className = classDescriptor.replace('/', '.'); + Class<?> generated = classLoader.getGeneratedClass(className, byteCode); + return generated; + } + + public static class BeanProperty { + private Class<?> type; + private String namespace; + private String name; + private String signature; + private String genericSignature; + private List<Annotation> jaxbAnnotaions = new ArrayList<Annotation>(); + private boolean element; + private boolean nillable; + + public BeanProperty(String namespace, String name, Class<?> javaClass, Type type, boolean isElement) { + super(); + this.namespace = namespace; + this.name = name; + this.signature = CodeGenerationHelper.getJAXWSSignature(javaClass); + this.type = javaClass; + this.genericSignature = CodeGenerationHelper.getJAXWSSignature(type); + this.element = isElement; + // FIXME: How to test nillable? + // this.nillable = (type instanceof GenericArrayType) || Collection.class.isAssignableFrom(javaClass) || javaClass.isArray(); + // TUSCANY-2389: Set the nillable consistent with what wsgen produces + this.nillable = javaClass.isArray(); + } + + public String getName() { + return name; + } + + public String getSignature() { + return signature; + } + + public String getGenericSignature() { + return genericSignature; + } + + public Class<?> getType() { + return type; + } + + public List<Annotation> getJaxbAnnotaions() { + return jaxbAnnotaions; + } + + public String getNamespace() { + return namespace; + } + + public boolean isElement() { + return element; + } + + public boolean isNillable() { + return nillable; + } + } + + public XMLAdapterExtensionPoint getXmlAdapters() { + return xmlAdapters; + } + + public void setXmlAdapters(XMLAdapterExtensionPoint xmlAdapters) { + this.xmlAdapters = xmlAdapters; + } + + protected static <T extends Annotation> T findAnnotation(Annotation[] anns, Class<T> annotationClass) { + for (Annotation a : anns) { + if (a.annotationType() == annotationClass) { + return annotationClass.cast(a); + } + } + return null; + } + + protected static List<Annotation> findJAXBAnnotations(Annotation[] anns) { + List<Annotation> jaxbAnnotation = new ArrayList<Annotation>(); + for (Class<? extends Annotation> c : KNOWN_JAXB_ANNOTATIONS) { + Annotation a = findAnnotation(anns, c); + if (a != null) { + jaxbAnnotation.add(a); + } + } + return jaxbAnnotation; + } + + protected List<Annotation> findJAXBAnnotations(Method method) { + List<Annotation> anns = new ArrayList<Annotation>(); + for (Class<? extends Annotation> c : KNOWN_JAXB_ANNOTATIONS) { + Annotation ann = method.getAnnotation(c); + if (ann != null) { + anns.add(ann); + } + } + return anns; + } + +} |