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:
parent
5c00818fcc
commit
9dc655d0fa
5 changed files with 292 additions and 34 deletions
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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>() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue