From 29ee2565f719b58a808160c961ff55e9c05c520f Mon Sep 17 00:00:00 2001 From: rfeng Date: Tue, 24 Jun 2008 22:13:38 +0000 Subject: Adding support to honor JAX-WS/JAXB annotations for the parameters and return type git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@671366 13f79535-47bb-0310-9956-ffa450edef68 --- .../interfacedef/java/jaxws/BaseBeanGenerator.java | 204 +++++++++++++++++++-- .../java/jaxws/FaultBeanGenerator.java | 2 +- .../java/jaxws/WrapperBeanGenerator.java | 104 +++++++++-- .../sca/interfacedef/java/jaxws/TestInterface.java | 11 ++ 4 files changed, 288 insertions(+), 33 deletions(-) (limited to 'java/sca/modules') diff --git a/java/sca/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/BaseBeanGenerator.java b/java/sca/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/BaseBeanGenerator.java index bfc633b00b..49a8552dc7 100644 --- a/java/sca/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/BaseBeanGenerator.java +++ b/java/sca/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/BaseBeanGenerator.java @@ -19,12 +19,24 @@ package org.apache.tuscany.sca.interfacedef.java.jaxws; +import java.lang.annotation.Annotation; +import java.lang.reflect.GenericArrayType; +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; @@ -41,6 +53,66 @@ public abstract class BaseBeanGenerator implements Opcodes { 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 JAVA_KEYWORDS = new HashMap(); + + 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> generatedClasses = Collections.synchronizedMap(new WeakHashMap>()); @@ -71,7 +143,7 @@ public abstract class BaseBeanGenerator implements Opcodes { declareConstructor(cw, classSignature); if (properties != null) { for (BeanProperty p : properties) { - boolean isMap = Map.class.isAssignableFrom(p.getType()); + boolean isElement = p.isElement() && (!Map.class.isAssignableFrom(p.getType())); String xmlAdapterClassSignature = null; if (xmlAdapters != null) { Class adapterClass = xmlAdapters.getAdapter(p.getType()); @@ -80,7 +152,7 @@ public abstract class BaseBeanGenerator implements Opcodes { } } declareProperty(cw, classDescriptor, classSignature, p.getName(), p.getSignature(), p - .getGenericSignature(), isMap, xmlAdapterClassSignature); + .getGenericSignature(), isElement, p.isNillable(), xmlAdapterClassSignature, p.getJaxbAnnotaions()); } } @@ -89,45 +161,75 @@ public abstract class BaseBeanGenerator implements Opcodes { 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 isMap, - String xmlAdapterClassSignature) { + boolean isElement, + boolean isNillable, + String xmlAdapterClassSignature, + List jaxbAnnotations) { if (propClassSignature.equals(propTypeSignature)) { propTypeSignature = null; } - declareField(cw, propName, propClassSignature, propTypeSignature, isMap, xmlAdapterClassSignature); + 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) { - if ("return".equals(propName)) { - return "_return"; - } else { - return propName; - } + String name = JAVA_KEYWORDS.get(propName); + return name != null ? name : propName; } protected void declareField(ClassWriter cw, String propName, String propClassSignature, String propTypeSignature, - boolean isMap, - String xmlAdapterClassSignature) { + boolean isElement, + boolean isNillable, + String xmlAdapterClassSignature, + List 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 (!isMap) { + 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); + } av0.visitEnd(); } @@ -137,6 +239,25 @@ public abstract class BaseBeanGenerator implements Opcodes { 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(); } @@ -320,16 +441,23 @@ public abstract class BaseBeanGenerator implements Opcodes { public static class BeanProperty { private Class type; + private String namespace; private String name; private String signature; private String genericSignature; + private List jaxbAnnotaions = new ArrayList(); + private boolean element; + private boolean nillable; - public BeanProperty(String name, Class javaClass, Type type) { + 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; + this.nillable = (type instanceof GenericArrayType); } public String getName() { @@ -347,6 +475,22 @@ public abstract class BaseBeanGenerator implements Opcodes { public Class getType() { return type; } + + public List getJaxbAnnotaions() { + return jaxbAnnotaions; + } + + public String getNamespace() { + return namespace; + } + + public boolean isElement() { + return element; + } + + public boolean isNillable() { + return nillable; + } } public XMLAdapterExtensionPoint getXmlAdapters() { @@ -356,4 +500,36 @@ public abstract class BaseBeanGenerator implements Opcodes { public void setXmlAdapters(XMLAdapterExtensionPoint xmlAdapters) { this.xmlAdapters = xmlAdapters; } + + protected static T findAnnotation(Annotation[] anns, Class annotationClass) { + for (Annotation a : anns) { + if (a.annotationType() == annotationClass) { + return annotationClass.cast(a); + } + } + return null; + } + + protected static List findJAXBAnnotations(Annotation[] anns) { + List jaxbAnnotation = new ArrayList(); + for (Class c : KNOWN_JAXB_ANNOTATIONS) { + Annotation a = findAnnotation(anns, c); + if (a != null) { + jaxbAnnotation.add(a); + } + } + return jaxbAnnotation; + } + + protected List findJAXBAnnotations(Method method) { + List anns = new ArrayList(); + for (Class c : KNOWN_JAXB_ANNOTATIONS) { + Annotation ann = method.getAnnotation(c); + if (ann != null) { + anns.add(ann); + } + } + return anns; + } + } diff --git a/java/sca/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/FaultBeanGenerator.java b/java/sca/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/FaultBeanGenerator.java index e81de324f1..40fbefa3ed 100644 --- a/java/sca/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/FaultBeanGenerator.java +++ b/java/sca/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/FaultBeanGenerator.java @@ -59,7 +59,7 @@ public class FaultBeanGenerator extends BaseBeanGenerator { // Add the field String field = pd.getName(); Method getter = pd.getReadMethod(); - props.add(new BeanProperty(field, getter.getReturnType(), getter.getGenericReturnType())); + props.add(new BeanProperty("", field, getter.getReturnType(), getter.getGenericReturnType(), false)); } } Collections.sort(props, new Comparator() { diff --git a/java/sca/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/WrapperBeanGenerator.java b/java/sca/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/WrapperBeanGenerator.java index d4b1d93ba3..785496f7b6 100644 --- a/java/sca/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/WrapperBeanGenerator.java +++ b/java/sca/modules/interface-java-jaxws/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxws/WrapperBeanGenerator.java @@ -19,11 +19,15 @@ package org.apache.tuscany.sca.interfacedef.java.jaxws; +import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; +import javax.jws.WebParam; +import javax.jws.WebResult; + import org.apache.tuscany.sca.interfacedef.java.impl.JavaInterfaceUtil; public class WrapperBeanGenerator extends BaseBeanGenerator { @@ -65,19 +69,36 @@ public class WrapperBeanGenerator extends BaseBeanGenerator { Class[] paramTypes = m.getParameterTypes(); Type[] genericParamTypes = m.getGenericParameterTypes(); - BeanProperty[] properties = new BeanProperty[paramTypes.length]; + Annotation[][] paramAnnotations = m.getParameterAnnotations(); + List properties = new ArrayList(); for (int i = 0; i < paramTypes.length; i++) { + String propNS = ""; String propName = "arg" + i; - properties[i] = new BeanProperty(propName, paramTypes[i], genericParamTypes[i]); + + WebParam webParam = findAnnotation(paramAnnotations[i], WebParam.class); + if (webParam != null && webParam.header()) { + continue; + } + WebParam.Mode mode = WebParam.Mode.IN; + if (webParam != null) { + mode = webParam.mode(); + if (webParam.name().length() > 0) { + propName = webParam.name(); + } + propNS = webParam.targetNamespace(); + } + if (mode.equals(WebParam.Mode.IN) || mode.equals(WebParam.Mode.INOUT)) { + java.lang.reflect.Type genericParamType = getHolderValueType(genericParamTypes[i]); + Class paramType = CodeGenerationHelper.getErasure(genericParamType); + BeanProperty prop = new BeanProperty(propNS, propName, paramType, genericParamType, true); + prop.getJaxbAnnotaions().addAll(findJAXBAnnotations(paramAnnotations[i])); + properties.add(prop); + } } wrapperClass = - generate(wrapperClassDescriptor, - wrapperClassSignature, - wrapperNamespace, - wrapperName, - properties, - cl); + generate(wrapperClassDescriptor, wrapperClassSignature, wrapperNamespace, wrapperName, properties + .toArray(new BeanProperty[properties.size()]), cl); generatedClasses.put(key, wrapperClass); } return wrapperClass; @@ -107,20 +128,67 @@ public class WrapperBeanGenerator extends BaseBeanGenerator { String wrapperClassDescriptor = wrapperClassName.replace('.', '/'); String wrapperClassSignature = "L" + wrapperClassDescriptor + ";"; + List properties = new ArrayList(); + // Collect all OUT, INOUT parameters as fields + Annotation[][] paramAnns = m.getParameterAnnotations(); + Class[] paramTypes = m.getParameterTypes(); + java.lang.reflect.Type[] genericParamTypes = m.getGenericParameterTypes(); + for (int i = 0; i < paramTypes.length; i++) { + WebParam webParam = findAnnotation(paramAnns[i], WebParam.class); + if (webParam != null) { + if (webParam.header() || webParam.mode() == WebParam.Mode.IN) { + continue; + } + } + if (!isHolder(genericParamTypes[i])) { + continue; + } + + List jaxb = findJAXBAnnotations(paramAnns[i]); + + java.lang.reflect.Type genericParamType = getHolderValueType(genericParamTypes[i]); + Class paramType = CodeGenerationHelper.getErasure(genericParamType); + + String paramNamespace = ""; + String paramName = "arg" + i; + + if (webParam != null) { + if (webParam.name().length() > 0) + paramName = webParam.name(); + if (webParam.targetNamespace().length() > 0) + paramNamespace = webParam.targetNamespace(); + } + + BeanProperty prop = new BeanProperty(paramNamespace, paramName, paramType, genericParamType, true); + prop.getJaxbAnnotaions().addAll(jaxb); + properties.add(prop); + } + + WebResult webResult = m.getAnnotation(WebResult.class); Class returnType = m.getReturnType(); - BeanProperty[] properties = null; - if (returnType != void.class) { - Type genericReturnType = m.getGenericReturnType(); + if (!((webResult != null && webResult.header()) || returnType == Void.TYPE)) { String propName = "return"; - properties = new BeanProperty[] {new BeanProperty(propName, returnType, genericReturnType)}; + String propNS = ""; + + if (webResult != null) { + if (webResult.name().length() > 0) { + propName = webResult.name(); + } + if (webResult.targetNamespace().length() > 1) { + propNS = webResult.targetNamespace(); + } + } + + List jaxb = findJAXBAnnotations(m.getAnnotations()); + + Type genericReturnType = m.getGenericReturnType(); + BeanProperty prop = new BeanProperty(propNS, propName, returnType, genericReturnType, true); + prop.getJaxbAnnotaions().addAll(jaxb); + properties.add(prop); } wrapperClass = - generate(wrapperClassDescriptor, - wrapperClassSignature, - wrapperNamespace, - wrapperName, - properties, - cl); + generate(wrapperClassDescriptor, wrapperClassSignature, wrapperNamespace, wrapperName, properties + .toArray(new BeanProperty[properties.size()]), cl); generatedClasses.put(key, wrapperClass); } return wrapperClass; diff --git a/java/sca/modules/interface-java-jaxws/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxws/TestInterface.java b/java/sca/modules/interface-java-jaxws/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxws/TestInterface.java index 115e89ef2a..a6a3375eff 100644 --- a/java/sca/modules/interface-java-jaxws/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxws/TestInterface.java +++ b/java/sca/modules/interface-java-jaxws/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxws/TestInterface.java @@ -24,6 +24,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import javax.jws.WebMethod; +import javax.jws.WebParam; +import javax.jws.WebResult; +import javax.xml.ws.Holder; + import org.osoa.sca.annotations.Remotable; /** @@ -52,4 +57,10 @@ public interface TestInterface { Map getGreetingsMap(Map namesMap); HashMap getGreetingsHashMap(HashMap namesMap); + + @WebMethod + @WebResult(name = "output") + String webMethod(@WebParam(name = "input", mode = WebParam.Mode.IN) + String in, @WebParam(name = "holder", mode = WebParam.Mode.INOUT) + Holder holder); } -- cgit v1.2.3