Thank you very much Daniel.

The XmlAdapter is fixing the issue. I've used the java_first_jaxws sample
in the CXF distribution as a template for the implementation.

But I have added a check for null value at the beginning of marshal and
unmarshal functions (to avoid NullPointerException):

    public StringStringMap marshal(Map<String, String> entries) throws
Exception{
    if (entries==null){
    return null;
    }
        [...]
    }

    public Map<String,String> unmarshal(StringStringMap ssm) throws
Exception {
    if (ssm==null){
    return null;
    }
        [...]
    }

Regards.
Johann

2011/12/8 Daniel Kulp <[email protected]>

>
> You've hit one of those "funny" things with JAXB that I've never quite
> understood.   Officially, JAXB does not support Maps.   However, the JAXB
> runtime does kind of handle them as long as you don't specifically tell
> JAXB
> about them by annotating it with and JAXB annotation.   As soon as you do,
> it
> barfs.
>
> The only way to handle this is to write an XmlAdapter that would map the
> Map
> into a class that JAXB would understand and then wire that in with
> @XmlJavaTypeAdapter along with your XmlElement annotation.
>
> You can see an example of how to handle maps like that in the
> java_first_jaxws
> sample in the CXF distribution.
>
> Dan
>
>
> On Wednesday, December 07, 2011 10:10:05 AM Default SPAM wrote:
> > 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(Illega
> > lAnnotationsException.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.
> --
> Daniel Kulp
> [email protected] - http://dankulp.com/blog
> Talend Community Coder - http://coders.talend.com
>

Reply via email to