/* * 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.reflect.Type; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.WeakHashMap; 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 COLLECTION_CLASSES = new HashMap(); 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"); } protected static final Map> generatedClasses = Collections.synchronizedMap(new WeakHashMap>()); 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 isMap = 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(), isMap, xmlAdapterClassSignature); } } // Close the generation cw.visitEnd(); return cw.toByteArray(); } protected void declareProperty(ClassWriter cw, String classDescriptor, String classSignature, String propName, String propClassSignature, String propTypeSignature, boolean isMap, String xmlAdapterClassSignature) { if (propClassSignature.equals(propTypeSignature)) { propTypeSignature = null; } declareField(cw, propName, propClassSignature, propTypeSignature, isMap, xmlAdapterClassSignature); decalreGetter(cw, classDescriptor, classSignature, propName, propClassSignature, propTypeSignature); declareSetter(cw, classDescriptor, classSignature, propName, propClassSignature, propTypeSignature); } protected String getFieldName(String propName) { if ("return".equals(propName)) { return "_return"; } else { return propName; } } protected void declareField(ClassWriter cw, String propName, String propClassSignature, String propTypeSignature, boolean isMap, String xmlAdapterClassSignature) { FieldVisitor fv; AnnotationVisitor av0; fv = cw.visitField(ACC_PROTECTED, getFieldName(propName), propClassSignature, propTypeSignature, null); // For Map property, we cannot have the XmlElement annotation if (!isMap) { av0 = fv.visitAnnotation("Ljavax/xml/bind/annotation/XmlElement;", true); av0.visit("name", propName); av0.visit("namespace", ""); 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(); } 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, "", "()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, "", "()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", "", "()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 name; private String signature; private String genericSignature; public BeanProperty(String name, Class javaClass, Type type) { super(); this.name = name; this.signature = CodeGenerationHelper.getJAXWSSignature(javaClass); this.type = javaClass; this.genericSignature = CodeGenerationHelper.getJAXWSSignature(type); } public String getName() { return name; } public String getSignature() { return signature; } public String getGenericSignature() { return genericSignature; } public Class getType() { return type; } } public XMLAdapterExtensionPoint getXmlAdapters() { return xmlAdapters; } public void setXmlAdapters(XMLAdapterExtensionPoint xmlAdapters) { this.xmlAdapters = xmlAdapters; } }