Hi all,
I would like to submit a question since I have noticed an inconsistency
between WSDL generated by "org.apache.cxf.tools.java2ws.JavaToWS" and
response sent by CXF.
> I have a service like this:
@WebService(endpointInterface = "be.eft.cbkv3.ws.WSExampleService",
serviceName = "WSExampleService")
public class WSExampleServiceImpl implements WSExampleService{
protected final Log log= LogFactory.getLog(this.getClass());
public WSExample getExample(String exampleId){
return new WSExample();
};
}
> This service is returning a WSExample that is a simple bean that contains
a Map:
public class WSExample implements Serializable{
/** identifier field */
private Long id;
/**
* @return Returns the id.
* @hibernate.id column = "ID" length = "19"
* generator-class = "native"
*/
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
/** An object containing all business data related to the auto-action
*/
private Map<String,String> arguments;
/**
* @hibernate.map cascade= "all" table= "CBK_AUTOACTIONARGS"
* @hibernate.key column= "CBK_AUTOACTIONID"
foreign-key="AAARG_CBKAAID_FK"
* @hibernate.index column= "NAME" type= "java.lang.String"
* @hibernate.element column= "VALUE" type= "java.lang.String"
* @return the arguments
*/
public Map<String, String> getArguments() {
return arguments;
}
public void setArguments(Map<String, String> arguments) {
this.arguments = arguments;
}
}
> The WSDL generated looks like:
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions name="ExampleService" targetNamespace="
http://ws.cbkv3.eft.be/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://ws.cbkv3.eft.be/" xmlns:xsd="
http://www.w3.org/2001/XMLSchema" xmlns:soap="
http://schemas.xmlsoap.org/wsdl/soap/">
<wsdl:types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="
http://ws.cbkv3.eft.be/" attributeFormDefault="unqualified"
elementFormDefault="unqualified" targetNamespace="http://ws.cbkv3.eft.be/">
<xs:complexType name="wsExample">
<xs:sequence>
<xs:element name="arguments">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" name="entry">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="key" type="xs:string"/>
<xs:element minOccurs="0" name="value" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element minOccurs="0" name="id" type="xs:long"/>
</xs:sequence>
</xs:complexType>
<xs:element name="getExample" type="getExample"/>
<xs:complexType name="getExample">
<xs:sequence>
<xs:element minOccurs="0" name="exampleId" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:element name="getExampleResponse" type="getExampleResponse"/>
<xs:complexType name="getExampleResponse">
<xs:sequence>
<xs:element minOccurs="0" name="return" type="wsExample"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
</wsdl:types>
<wsdl:message name="getExampleResponse">
<wsdl:part name="parameters" element="tns:getExampleResponse">
</wsdl:part>
</wsdl:message>
<wsdl:message name="getExample">
<wsdl:part name="parameters" element="tns:getExample">
</wsdl:part>
</wsdl:message>
<wsdl:portType name="WSExampleService">
<wsdl:operation name="getExample">
<wsdl:input name="getExample" message="tns:getExample">
</wsdl:input>
<wsdl:output name="getExampleResponse"
message="tns:getExampleResponse">
</wsdl:output>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="WSExampleServiceSoapBinding"
type="tns:WSExampleService">
<soap:binding style="document" transport="
http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getExample">
<soap:operation soapAction="" style="document"/>
<wsdl:input name="getExample">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="getExampleResponse">
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="ExampleService">
<wsdl:port name="WSExampleServiceImplPort"
binding="tns:WSExampleServiceSoapBinding">
<soap:address location="http://localhost:9090/WSExampleServiceImplPort
"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
> That's looks more or less fine, but once we receive a response from the
server when there is no arguments (the WSExample#arguments is null) then we
receive something like:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ws="http://ws.cbkv3.eft.be/">
<soapenv:Header/>
<soapenv:Body>
<ws:getExampleResponse>
<return>
<id>myId</id>
</return>
</ws:getExampleResponse>
</soapenv:Body>
</soapenv:Envelope>
> This response is not "compliant" with the WSDL since <arguments> should
be present, we should receive from server (running CXF):
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ws="http://ws.cbkv3.eft.be/">
<soapenv:Header/>
<soapenv:Body>
<ws:getExampleResponse>
<return>
<arguments>
</arguments>
<id>myId</id>
</return>
</ws:getExampleResponse>
</soapenv:Body>
</soapenv:Envelope>
To workaround this, I can explicitely (and manually) add 'minOccurs="0"
nillable="true"' to 'arguments' element:
<xs:element name="arguments" minOccurs="0" nillable="true">
That way, my WSDL is consistent with what CXF is returning.
But, it means we also cannot rely on the WSDL dynamically generated (with
?wsdl) once my service is deployed.
I tried to add "@XmlElement(required=false, nillable=true)" annotation to
getArguments() function but I got an error like:
Caused by: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 2
counts of IllegalAnnotationExceptions
[java] java.util.Map is an interface, and JAXB can't handle interfaces.
[java] this problem is related to the following location:
[java] at java.util.Map
[java] at public java.util.Map
be.eft.cbkv3.data.schema.WSExample.getArguments()
[java] at be.eft.cbkv3.data.schema.WSExample
[java] java.util.Map does not have a no-arg default constructor.
[java] this problem is related to the following location:
[java] at java.util.Map
[java] at public java.util.Map
be.eft.cbkv3.data.schema.WSExample.getArguments()
[java] at be.eft.cbkv3.data.schema.WSExample
[java] at
com.sun.xml.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:106)
[...]
It sounds logic that if "arguments can be null" (and it can) we can get
SOAP response with no <arguments> tag then CXF response sounds correct to
me.
But WSDL generated should then contains <... minOccurs="0" nillable="true">
instead of nothing (knowing that when such arguments are not specified,
defaults are <... minOccurs="1" nillable="false">.
Any idea how to fix this inconsistency?
Regards.
Johann
NB: Tried with CXF 2.2.9 and CXF 2.5.0.