Why classes generated by wsimport requires JAXBElement<ClassName> parameters?
Asked Answered
P

2

5

I have a WSDL file which is from an Axis2 Web Service. When I generate a client stub using wsimport given the WSDL file, the resulting classes require JAXBElement paramaters. Why is it like that?

Sample Method from one of the Generated Classes:

JAXBElement<DataBean> value;

public void setValue(JAXBElement<DataBean> value)
{
    this.value = ((JAXBElement<DataBean>) value);
}

I am expecting it to look like this (without the JAXBElement):

DataBean value;

public void setValue(DataBean value)
{
    this.value= (DataBean) value;
}

The tutorials I saw on the net does not set the classes to JAXBElement. What could be the problem? Please take note that the server is an Axis2 web service and the WSDL file is auto-generated by Axis2. The assumption is I have no control over the server.

How can I make it in such a way that wsimport won't convert the parameters to JAXBElements?

Below is an excerpt from the WSDL file: (I ignored some of the tags to include only the essential tags)

<xs:element name="getData">
    <xs:complexType>
        <xs:sequence>
            <xs:element minOccurs="0" name="getData" nillable="true" type="ax220:getData"/>
        </xs:sequence>
    </xs:complexType>
</xs:element>

<xs:complexType name="getData">
    <xs:sequence>
        <xs:element minOccurs="0" name="value" nillable="true" type="ax219:DataBean"/>
    </xs:sequence>
</xs:complexType>

<wsdl:message name="getDataRequest">
    <wsdl:part name="parameters" element="ns:getData"/>
</wsdl:message>

<wsdl:message name="getDataResponse">
    <wsdl:part name="parameters" element="ns:getDataResponse"/>
</wsdl:message>

<wsdl:operation name="getData">
    <wsdl:input message="ns:getDataRequest" wsaw:Action="urn:getData"/>
    <wsdl:output message="ns:getDataResponse" wsaw:Action="urn:getDataResponse"/>
</wsdl:operation>

<wsdl:operation name="getData">
    <soap:operation soapAction="urn:getData" style="document"/>
    <wsdl:input>
        <soap:body use="literal"/>
    </wsdl:input>
    <wsdl:output>
        <soap:body use="literal"/>
    </wsdl:output>
</wsdl:operation>

<wsdl:operation name="getData">
    <soap12:operation soapAction="urn:getData" style="document"/>
    <wsdl:input>
        <soap12:body use="literal"/>
    </wsdl:input>
    <wsdl:output>
        <soap12:body use="literal"/>
    </wsdl:output>
</wsdl:operation>

<wsdl:operation name="getData">
    <http:operation location="getData"/>
    <wsdl:input>
        <mime:content type="text/xml" part="parameters"/>
    </wsdl:input>
    <wsdl:output>
        <mime:content type="text/xml" part="parameters"/>
    </wsdl:output>
</wsdl:operation>
Provender answered 31/8, 2012 at 7:56 Comment(2)
Can you post the parts of the WSDL where DataBean is defined and used in a message and operation?Whit
@joergl: I modified my post to include the requested details.Provender
W
2

To begin with: I don't think this can be done. That is, I don't think you can tell wsimport to generate the classes differently. However, I can tell you how to modify the WSDL in a way that generates the schema differently and that could still enable you to talk to the service.

I took the type definitions from the WSDL, adjusted the name of the complexType and added the a type for DataBean that was missing above. I pasted that to a schema and compiled the schema with xjc, the JAXB schema compiler, which is used by wsimport to generate classes from the type defintions. Here is the schema:

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/DataBean"
    xmlns:tns="http://www.example.org/DataBean" elementFormDefault="qualified"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <xs:element name="getData">
        <xs:complexType>
            <xs:sequence>
                <xs:element minOccurs="0" name="getDataType" type="tns:getDataType" />
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:complexType name="getDataType">
        <xs:sequence>
            <xs:element minOccurs="0" name="value" type="tns:DataBean" />
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="DataBean">
        <xs:simpleContent>
            <xs:extension base="xs:int" />
        </xs:simpleContent>
    </xs:complexType>
</schema>

You don't need any special options for the compiler, simply execute xjc and point it to the schema file, then it will compile the source files.

The generated classes do not use JAXBElement as method parameters. That is they look like that:

protected DataBean value;

public DataBean getValue() {
    return value;
}

Why is this? I removed the nillable="true" attributes from the element defintions and this did the trick. nillable="true" states that explicit null values are legal here:

<DataBean></DataBean> 

If you remove this attribute, your code will run into problems if the service actually writes null values in there. But after all the WSDL is generated and maybe Axis2 just thinks the nillable should be in there for some reason, although the implementation never actually uses it. If you are lucky, it does not and everything will work fine, although you modified the WSDL.

I hope this helps! If not, then at least I have learned something today ;-)

Whit answered 31/8, 2012 at 11:1 Comment(5)
Hi! Thanks! Will try this out. :) Hope it works. I will keep you updated. So basically, you're saying that Axis2 is not JAXWS compliant and as such, there is no way for wsimport to generate the WSDL generated by Axis2 without manually modifying the WSDL? Did I understand you correctly?Provender
Well, no. Axis2 is JAX-WS compliant, at least largely. I haven't tested it in detail, but I am sure it implements most parts and fails to implement some ;-) The problem here is rather some edge case of JAXB schema generation. I should be fixed at the root (the web service, by changing the annotations to not generate the nillable=true). As you can't do this, the local work around is the best you can get.Whit
Thanks for the clarification! I thought I read somewhere that Axis2 is not JAX-WS so I stayed away from it when I learned that the service I'm going to connect to is JAX-WS. Also, when I'm generating a client stub for Axis2, JAXB is not included in the list of databinding options. (I'm using Eclipse.) The list of databinding options only includes ADB, XMLBeans, JIBX and None. Which option should I select to use the JAXWS binding?Provender
None of these ;-) Axis2 also supports JAXB, but does not list this in its official documentation: axis.apache.org/axis2/java/core/tools/CodegenToolReference.html That is poor... Well, here is an article that explains how to use JAXB with Axis2 ibm.com/developerworks/java/library/j-jws8/index.html The short answer is that you should use: -d jaxbriWhit
Thanks! :D Maybe, I should stop generating my client stubs the lazy way (Hello, IDE). I will check your link.Provender
E
7

As read on this page :

http://www.techdevtips.com/java/java-webservice-client-how-to-remove-jaxbelement

use a data binding file with this code :

<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings
  xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0"
  xmlns:xjc= "http://java.sun.com/xml/ns/jaxb/xjc" jaxb:extensionBindingPrefixes="xjc">
  <jaxb:globalBindings generateElementProperty="false">
    <xjc:simple />
  </jaxb:globalBindings>
</jaxb:bindings>

and use it in your wsimport ant task by filling the binding attribute (or -b flag argument if you use the runnable)

Cheers :)

Ewer answered 27/5, 2014 at 16:3 Comment(0)
W
2

To begin with: I don't think this can be done. That is, I don't think you can tell wsimport to generate the classes differently. However, I can tell you how to modify the WSDL in a way that generates the schema differently and that could still enable you to talk to the service.

I took the type definitions from the WSDL, adjusted the name of the complexType and added the a type for DataBean that was missing above. I pasted that to a schema and compiled the schema with xjc, the JAXB schema compiler, which is used by wsimport to generate classes from the type defintions. Here is the schema:

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/DataBean"
    xmlns:tns="http://www.example.org/DataBean" elementFormDefault="qualified"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <xs:element name="getData">
        <xs:complexType>
            <xs:sequence>
                <xs:element minOccurs="0" name="getDataType" type="tns:getDataType" />
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:complexType name="getDataType">
        <xs:sequence>
            <xs:element minOccurs="0" name="value" type="tns:DataBean" />
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="DataBean">
        <xs:simpleContent>
            <xs:extension base="xs:int" />
        </xs:simpleContent>
    </xs:complexType>
</schema>

You don't need any special options for the compiler, simply execute xjc and point it to the schema file, then it will compile the source files.

The generated classes do not use JAXBElement as method parameters. That is they look like that:

protected DataBean value;

public DataBean getValue() {
    return value;
}

Why is this? I removed the nillable="true" attributes from the element defintions and this did the trick. nillable="true" states that explicit null values are legal here:

<DataBean></DataBean> 

If you remove this attribute, your code will run into problems if the service actually writes null values in there. But after all the WSDL is generated and maybe Axis2 just thinks the nillable should be in there for some reason, although the implementation never actually uses it. If you are lucky, it does not and everything will work fine, although you modified the WSDL.

I hope this helps! If not, then at least I have learned something today ;-)

Whit answered 31/8, 2012 at 11:1 Comment(5)
Hi! Thanks! Will try this out. :) Hope it works. I will keep you updated. So basically, you're saying that Axis2 is not JAXWS compliant and as such, there is no way for wsimport to generate the WSDL generated by Axis2 without manually modifying the WSDL? Did I understand you correctly?Provender
Well, no. Axis2 is JAX-WS compliant, at least largely. I haven't tested it in detail, but I am sure it implements most parts and fails to implement some ;-) The problem here is rather some edge case of JAXB schema generation. I should be fixed at the root (the web service, by changing the annotations to not generate the nillable=true). As you can't do this, the local work around is the best you can get.Whit
Thanks for the clarification! I thought I read somewhere that Axis2 is not JAX-WS so I stayed away from it when I learned that the service I'm going to connect to is JAX-WS. Also, when I'm generating a client stub for Axis2, JAXB is not included in the list of databinding options. (I'm using Eclipse.) The list of databinding options only includes ADB, XMLBeans, JIBX and None. Which option should I select to use the JAXWS binding?Provender
None of these ;-) Axis2 also supports JAXB, but does not list this in its official documentation: axis.apache.org/axis2/java/core/tools/CodegenToolReference.html That is poor... Well, here is an article that explains how to use JAXB with Axis2 ibm.com/developerworks/java/library/j-jws8/index.html The short answer is that you should use: -d jaxbriWhit
Thanks! :D Maybe, I should stop generating my client stubs the lazy way (Hello, IDE). I will check your link.Provender

© 2022 - 2024 — McMap. All rights reserved.