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.

Reply via email to