Apologies for the length of this but I wanted to include WSDL and generated code to give a complete picture.
I've been trying to get simple Java client code generated for a service that has no input but does have some output. Defining an input message with a part that has an empty element produces Java code, via WSDL2Java, that works fine, provided I pass a null parameter. The service method in the generated stub is trying to pass back the Java object I want and the Axis code can deserialize it fine.
However, if I define an input message with no parts, the generated stub includes a no-arguments method, which is what I want, but it tries to return an object typed to a different class, the class generated to represent to SOAP response body. However, the actual response from the service is the same in both cases, so the no-arguments method fails with a class cast exception.
It seems that the Axis code is trying to deserialize the response as though all the elements below the body root are attributes of the root class. I've noticed that the generated stub for the no-arguments version sets the operation as document/literal instead of wrapped/literal, and sets different return properties for the operation. If I alter the generated stub to match the stub generated for the single argument version (apart from keeping the no-argument version of the service method), then it works fine.
Does anyone know how to get the Axis WSDL2Java tool to generate working code for the no-arguments version? I've included the WSDL and generated code below, in case my explanation is not clear.
Thanks for any help.
Tony
The WSDL (without the XML/SOAP namespace declarations) for the single argument version is something like:
<?xml version="1.0" encoding="utf-8"?>
<definitions xmlns:services="uri:myServicesNameSpace" xmlns:mine="uri:myNameSpace" targetNamespace="uri:myServicesNameSpace">
<types>
<xs:schema targetNamespace="uri:myNameSpace" xmlns:my="uri:myNameSpace" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:complexType name="myObjectType">
<xs:sequence>
<xs:element name="id" type="xs:integer" nillable="false"/>
<xs:element name="mf" type="xs:string" nillable="false"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="myObjectList">
<xs:sequence>
<xs:element ref="my:thing" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:element name="thing" nillable="false" type="my:myObjectType"/>
<xs:element name="things" nillable="false" type="my:myObjectList"/>
</xs:schema>
<xs:schema elementFormDefault="qualified" targetNamespace="uri:myServicesNameSpace">
<xs:complexType name="serviceResponse">
<xs:sequence>
<xs:element ref="mine:things"/>
</xs:sequence>
</xs:complexType>
<xs:element name="getObjects">
</xs:element>
<xs:element name="objectDescriptions" type="services:serviceResponse">
</xs:element>
</xs:schema>
</types>
<message name="getObjectsRequest">
<part name="getObjects" element="services:getObjects"/>
</message>
<message name="getObjectsReply">
<part name="getObjects" element="services:objectDescriptions"/>
</message>
<portType name="objectsPortType">
<operation name="getObjects">
<input message="services:getObjectsRequest"/>
<output message="services:getObjectsReply"/>
</operation>
</portType>
<binding name="ObjectsBinding" type="services:objectsPortType">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="getObjects">
<soap:operation soapAction="getObjects" style="document"/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="ObjectsLookup">
<port name="ObjectsPort" binding="services:ObjectsBinding">
<soap:address location="http://my.com:8080/axis/services/ObjectsLookup"/>
</port>
</service>
</definitions>
The relevant sections of the generated stub are:
public class ObjectsBindingStub extends org.apache.axis.client.Stub implements myServicesNameSpace.ObjectsPortType {
...
static {
_operations = new org.apache.axis.description.OperationDesc[1];
org.apache.axis.description.OperationDesc oper;
oper = new org.apache.axis.description.OperationDesc();
oper.setName("getObjects");
oper.addParameter(new javax.xml.namespace.QName("uri:myServicesNameSpace", "getObjects"), new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "anyType"), java.lang.Object.class, org.apache.axis.description.ParameterDesc.IN, false, false);
oper.setReturnType(new javax.xml.namespace.QName("uri:myNameSpace", "myObjectList"));
oper.setReturnClass(myNameSpace.MyObjectList.class);
oper.setReturnQName(new javax.xml.namespace.QName("uri:myNameSpace", "things"));
oper.setStyle(org.apache.axis.enum.Style.WRAPPED);
oper.setUse(org.apache.axis.enum.Use.LITERAL);
_operations[0] = oper;
}
....
public myNameSpace.MyObjectList getObjects(java.lang.Object getObjects) throws java.rmi.RemoteException {
if (super.cachedEndpoint == null) {
throw new org.apache.axis.NoEndPointException();
}
org.apache.axis.client.Call _call = createCall();
_call.setOperation(_operations[0]);
_call.setUseSOAPAction(true);
_call.setSOAPActionURI("getObjects");
_call.setEncodingStyle(null);
_call.setProperty(org.apache.axis.client.Call.SEND_TYPE_ATTR, Boolean.FALSE);
_call.setProperty(org.apache.axis.AxisEngine.PROP_DOMULTIREFS, Boolean.FALSE);
_call.setSOAPVersion(org.apache.axis.soap.SOAPConstants.SOAP11_CONSTANTS);
_call.setOperationName(new javax.xml.namespace.QName("uri:myServicesNameSpace", "getObjects"));
setRequestHeaders(_call);
setAttachments(_call);
java.lang.Object _resp = _call.invoke(new java.lang.Object[] {getObjects});
if (_resp instanceof java.rmi.RemoteException) {
throw (java.rmi.RemoteException)_resp;
}
else {
extractAttachments(_call);
try {
return (myNameSpace.MyObjectList) _resp;
} catch (java.lang.Exception _exception) {
return (myNameSpace.MyObjectList) org.apache.axis.utils.JavaUtils.convert(_resp, myNameSpace.MyObjectList.class);
}
}
}
}
This is all fine. However, when I alter the WSDL so that the input message becomes:
<message name="getObjectsRequest">
</message>
Then the relevant part of the generated stub is something like this:
public class ObjectsBindingStub extends org.apache.axis.client.Stub implements myServicesNameSpace.ObjectsPortType {
...
static {
_operations = new org.apache.axis.description.OperationDesc[1];
org.apache.axis.description.OperationDesc oper;
oper = new org.apache.axis.description.OperationDesc();
oper.setName("getObjects");
oper.setReturnType(new javax.xml.namespace.QName("uri:myServicesNameSpace", "serviceResponse"));
oper.setReturnClass(myServicesNameSpace.ServiceResponse.class);
oper.setReturnQName(new javax.xml.namespace.QName("uri:myServicesNameSpace", "objectDescriptions"));
oper.setStyle(org.apache.axis.enum.Style.DOCUMENT);
oper.setUse(org.apache.axis.enum.Use.LITERAL);
_operations[0] = oper;
}
...
public myServicesNameSpace.ServiceResponse getObjects() throws java.rmi.RemoteException {
if (super.cachedEndpoint == null) {
throw new org.apache.axis.NoEndPointException();
}
org.apache.axis.client.Call _call = createCall();
_call.setOperation(_operations[0]);
_call.setUseSOAPAction(true);
_call.setSOAPActionURI("getObjects");
_call.setEncodingStyle(null);
_call.setProperty(org.apache.axis.client.Call.SEND_TYPE_ATTR, Boolean.FALSE);
_call.setProperty(org.apache.axis.AxisEngine.PROP_DOMULTIREFS, Boolean.FALSE);
_call.setSOAPVersion(org.apache.axis.soap.SOAPConstants.SOAP11_CONSTANTS);
_call.setOperationName(new javax.xml.namespace.QName("", "getObjects"));
setRequestHeaders(_call);
setAttachments(_call);
java.lang.Object _resp = _call.invoke(new java.lang.Object[] {});
if (_resp instanceof java.rmi.RemoteException) {
throw (java.rmi.RemoteException)_resp;
}
else {
extractAttachments(_call);
try {
return (myServicesNameSpace.ServiceResponse) _resp;
} catch (java.lang.Exception _exception) {
return (myServicesNameSpace.ServiceResponse) org.apache.axis.utils.JavaUtils.convert(_resp, myServicesNameSpace.ServiceResponse.class);
}
}
}
}
- WSDL for no-arg operation in document style Phil McCarthy
- Re: WSDL for no-arg operation in document style tony . q . weddle
- tony . q . weddle
