TUSCANY-2389 allow null elements in object array to pass

git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@685876 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
slaws 2008-08-14 12:55:24 +00:00
parent 5c00818fcc
commit 9dc655d0fa
5 changed files with 292 additions and 34 deletions

View file

@ -567,7 +567,6 @@ public class StandardTypesDatabindingTestCase {
* Service method invoked is getNewObjectArray.
*/
@Test
@Ignore("TUSCANY-2389")
public void testWSNewObjectArray() throws Exception {
StandardTypesServiceClient serviceClient =
domain.getService(StandardTypesServiceClient.class, "StandardTypesServiceClientWSComponent");

View file

@ -19,12 +19,23 @@
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;
@ -41,6 +52,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<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<?>>());
@ -71,7 +142,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 +151,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 +160,77 @@ 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<Annotation> 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<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 (!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);
}
// FIXME:
// av0.visit("required", Boolean.FALSE);
av0.visitEnd();
}
@ -137,6 +240,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 +442,26 @@ 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<Annotation> jaxbAnnotaions = new ArrayList<Annotation>();
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;
// 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() {
@ -347,6 +479,22 @@ public abstract class BaseBeanGenerator implements Opcodes {
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() {
@ -356,4 +504,36 @@ public abstract class BaseBeanGenerator implements Opcodes {
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;
}
}

View file

@ -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<BeanProperty>() {

View file

@ -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<BeanProperty> properties = new ArrayList<BeanProperty>();
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<BeanProperty> properties = new ArrayList<BeanProperty>();
// 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<Annotation> 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<Annotation> 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;

View file

@ -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<String, String> getGreetingsMap(Map<String, String> namesMap);
HashMap<String, String> getGreetingsHashMap(HashMap<String, String> namesMap);
@WebMethod
@WebResult(name = "output")
String webMethod(@WebParam(name = "input", mode = WebParam.Mode.IN)
String in, @WebParam(name = "holder", mode = WebParam.Mode.INOUT)
Holder<String> holder);
}