[axis2] WSDL2JAVA with XMLBean binding does not create instance of the derived
type or ignore xsi:type in the xml
-----------------------------------------------------------------------------------------------------------------
Key: AXIS2-1938
URL: https://issues.apache.org/jira/browse/AXIS2-1938
Project: Apache Axis 2.0 (Axis2)
Issue Type: Bug
Components: databinding
Affects Versions: 1.1
Environment: Windows XP, tomcat 5.5, Axis2 1.1
Reporter: Bo Xie
There are basically two issues.
1. The java objects created does not use the xsi:type in the XML. In my case,
the xsi:type is for derived type, but the object created is still of base type.
2. The XML string generated from the client side has the xsi:type for Address
object, so the service see it but did not generate the derived type according
to the xsi:type(this is the issue reported above). But the server side
generated XML string does not have the xsi:type for the objects, so the object
XML string does not have xsi:type when the message received on the client side.
Why the xsi:type is missing in this case? In both cases, I used types derived
from the Address type. The client and service code are based on the XMLBean
quickstart sample.
Attached are
1. the WSDL file.
2.The build file that you can check if the WSDL2JAVA is proper for my case.
3. The client code
4. The server code.
Below are the email exchange with Ajith Ranabahu.
Subject: [axis2] WSDL2JAVA with XMLBean binding does not create instance of the
derived type
------------------------
From: Bo Xie <[EMAIL PROTECTED]>
To: [email protected]
Date: Tue, Jan 2, 2007 at 7:45 PM
Hi there,
I am new to axis2 with XMLBean data binding, please help me with the
following issue.
I modified the quickstart sample XMLBean program to try a WSDL with the
following types. The type US-Address is a derived from type Address. I would
like to create a service operation updateAddresses to change addresses of a
company based on a symbol. The addresses is an array that can take either
Address or USAddress instances.
<xs:complexType name="Address">
<xs:sequence>
<xs:element name="name" type="xs:string" minOccurs="0"/>
<xs:element name="street" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="US-Address">
<xs:complexContent>
<xs:extension base="ipo:Address">
<xs:sequence>
<xs:element name="state" type="ipo:US-State"/>
<xs:element name="zip" type="xs:positiveInteger"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="updateAddresses">
<xs:complexType>
<xs:sequence>
<xs:element name="symbol" type="xs:string"
nillable="true"/>
<xs:element name="addresses" type="ipo:Address"
maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
I used WSDL2JAVA with XMLBean data binding to generate the skeleton and
stub code. All looks great and the SOAP exchange looks fine too.
In the client code, I created one instance if USAddress and one instance
of Address and put them into the addresses list. In the SOAP request message,
the instances are as shown as follows below. Note, xsi-type for the instance
indicate the correct types which is nice.
<soapenv:Body>
<updateAddresses xmlns="http://quickstart.samples/xsd">
<symbol>XYZ</symbol>
<addresses xmlns:xsi="http;//www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="
http://quickstart.samples/xsd" xsi:type="xsd:US-Address">
<name>company name</name>
<city>Sunnyvale</city>
<state>CA</state>
<zip>94087</zip>
</addresses>
<addresses xmlns:xsi="http;//www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://quickstart.samples/xsd
" xsi:type="xsd:Address">
<name>company name</name>
<city>Hong Kong</city>
</addresses>
</updateAddresses>
</soapenv:Body>
The problem is when the XML object mapped into java object on the service
side, all the XML address object passed to the skeleton are all of Address
type. I would expect one instance be Address type, another be USAddress type.
Since xsi-type in the SOAP message has the right type, why the XMLBean object
is not created as the derived type? Is there any option in WSDL2JAVA to make
this work?
From the XMLBean Address java object, how can I access the xsi-type
attribute that was available in the XML string?
If I am not heading the right direction, can anyone suggest some
alternatives?
Thanks for your time!
-Bo
--------
From: Ajith Ranabahu <[EMAIL PROTECTED]>
Reply-To: [email protected]
To: [email protected]
Date: Wed, Jan 3, 2007 at 5:16 AM
Hi,
The reason here is that you have set the type of the addresses element
to be 'Address' rather than USAddress (the code generator would put
the reference for the Address rather than the USAddress). However
since the xsi:type attribute is present the deserializer should create
the right object and you can just use a type cast to get to the right
object.
HTH
Ajith
[Quoted text hidden]
--
Ajith Ranabahu
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
--------
From: Bo Xie <[EMAIL PROTECTED]>
Reply-To: [email protected]
To: [email protected]
Date: Wed, Jan 3, 2007 at 7:55 AM
Thanks Ajith for the quick response.
I have tried to use the instanceof to test if the instance is USAddress,
but the test returns false. Without that, the type cast is not safe as
the Address list can have items of either Address or USAddress. My
question here is should the java instance created from XML be of type
USAddress even though the signature is Address. Is there anyway to make
this happen?
Thanks,
-Bo
[Quoted text hidden]
[Quoted text hidden]
--------
From: Ajith Ranabahu <[EMAIL PROTECTED]>
Reply-To: [email protected]
To: [email protected]
Date: Wed, Jan 3, 2007 at 8:20 AM
Hi,
Since the xsi:type attribute is present and points to the USAddress,
the generated object should be of type USAddress. Perhaps the problem
is the way you check the instanceof. I mean XMLBeans should have
generated a getAddresses method to updateAddress ? (It's a little bit
weird how XMLBeans treats these schemas but I'm guessing)
If you can use a debugger and go through the object hierarchy at
runtime you should be able to figure this out
Ajith
[Quoted text hidden]
--
Ajith Ranabahu
[Quoted text hidden]
--------
From: Bo Xie <[EMAIL PROTECTED]>
To: [email protected]
Date: Wed, Jan 3, 2007 at 10:19 AM
Thanks Ajith. Could you be more specific on how to figure out the right type of
the instance? Here is the code snippet and the output on the service side.
The getAddressArray indeed returns Address[] which is good. But the instanceof
always returns Address even for USAddress instance. The interesting thing is
the toString output of the addr variable. It includes the correct xsi-type for
each instance. So how can I do the correct instanceof to figure the right type
to cast in this case?
Thanks,
-Bo
----Code snippet----
public void
updateAddresses(samples.quickstart.service.xmlbeans.xsd.UpdateAddressesDocument
param3)
{
//Todo fill this with the necessary business logic
String symbol = param3.getUpdateAddresses().getSymbol();
System.err.println(getCurrentTime()+"- Update Symbol:" + symbol);
Address[] addrs = param3.getUpdateAddresses ().getAddressesArray();
for (int i = 0; i < addrs.length; i++) {
Address addr = addrs[i];
if(addr instanceof USAddress) System.err.println("USAddress
instance");
if(addr instanceof Address) System.err.println("Address instance");
System.err.println(addr.getClass().getName()+":"+addr);
}
...}
----Output from the code ----
Address instance
samples.quickstart.service.xmlbeans.xsd.impl.AddressImpl: <xml-fragment
xsi:type="xsd:US-Address" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd=" http://quickstart.samples/xsd"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<name xmlns=" http://quickstart.samples/xsd">company name</name>
<city xmlns="http://quickstart.samples/xsd">Sunnyvale</city>
<state xmlns=" http://quickstart.samples/xsd">CA</state>
<zip xmlns="http://quickstart.samples/xsd">94087</zip>
</xml-fragment>
Address instance
samples.quickstart.service.xmlbeans.xsd.impl.AddressImpl:<xml-fragment
xsi:type="xsd:Address" xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance"
xmlns:ns1="http://quickstart.samples/xsd"
xmlns:xsd="http://quickstart.samples/xsd "
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<name xmlns="http://quickstart.samples/xsd ">company</name>
<city xmlns="http://quickstart.samples/xsd">Hong Kong</city>
</xml-fragment>
[Quoted text hidden]
--------
From: Ajith Ranabahu <[EMAIL PROTECTED]>
Reply-To: [email protected]
To: [email protected]
Date: Wed, Jan 3, 2007 at 5:16 PM
Hi,
It seems to me that you have to go one level deep. See whether there
is a getAddress method in the Address class.
XMLBeans generates a lot of classes and things are a bit confusing
specially when types and elements have similar names. AFAIK XMLBeans
generates a class per type and element. So there would be a class
generated for the address type and also for the address element. My
guess is you have to check the address type object instead of the
address element object.
Ajith
[Quoted text hidden]
--
[Quoted text hidden]
--------
From: Ramesh Gurunathan <[EMAIL PROTECTED]>
Reply-To: [email protected]
To: [email protected]
Date: Wed, Jan 3, 2007 at 8:32 PM
Hi,
What you are trying to achieve is the value inheritance in XML. I
think, unfortunately, the web services / XML / SOAP community is
paying less attention to this topic. I encountered the same issue with
XMLBeans binding. It forced me to change the XML schema. I introduced
a new complex type with a 'choice'
<complexType name="Address">
<choice>
<element name="USAddress" type="USAddress"/>
<element name="OtherAddress" type="OtherAddress"/>
</choice>
</complexType>
<xs:complexType name="OtherAddress">
<xs:sequence>
<xs:element name="name" type="xs:string" minOccurs="0"/>
<xs:element name="street" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="USAddress">
<xs:complexContent>
<xs:extension base="ipo:OtherAddress">
<xs:sequence>
<xs:element name="state" type="ipo:US-State"/>
<xs:element name="zip" type="xs:positiveInteger"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="updateAddresses">
<xs:complexType>
<xs:sequence>
<xs:element name="symbol" type="xs:string" nillable="true"/>
<xs:element name="addresses" type="Address" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</element>
If you generate XML beans types with above changes, it will generate a
Address type object which will have methods to check whether USAddress
is set or the Other Address. No need of instanceof check. Do take a
look at the generated method signatures of the Address XML type
object, it should give you an idea to play with it.
That said, this is just an another way of handling inheritance. I
would like to see XML beans to inherantly support the polymorphism.
Ramesh
[Quoted text hidden]
--------
From: Bo Xie <[EMAIL PROTECTED]>
To: [email protected]
Date: Wed, Jan 3, 2007 at 10:50 PM
Hi Ajith,
The Address class only has getter and setter for name, city etc. No
getAddress. Do you see this ignoring of xsi:type in creating instance as a bug?
Besides using choice option as Ramesh suggested, do we run out of luck here?
I am a little hesitate to use choice as in my case, the choice list changes
quite fast. Keeping track of the exhaustive list of all the choices is a
challenge.
Thanks,
-Bo
[Quoted text hidden]
--------
From: Ajith Ranabahu <[EMAIL PROTECTED]>
Reply-To: [email protected]
To: [email protected]
Date: Thu, Jan 4, 2007 at 5:08 AM
Hi,
> Hi Ajith,
>
> The Address class only has getter and setter for name, city etc. No
> getAddress. Do you see this ignoring of xsi:type in creating instance as a
> bug?
Yep. It is a bug. But AFAIK it was reported to be working. In any case
you can file a Jira with your schema.
Ajith
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
https://issues.apache.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]