Hi Jacques-Olivier, great find thanks,as you say WSIF should not to be AXIS
dependant for the complex type mapping and this is a pretty serious
problem.
Whats going wrong is that the AXIS bean deserialiser
(org.apache.axis.encoding.ser.BeanDeserializer) in the method onStartChild
tries to find a BeanPropertyDescriptor for the XML element to be
deserialised from the propertyMap. The propertyMap has been populated with
all the properties of the bean by the
org.apache.axis.utils.BeanUtils.getPropertyDescriptors which uses
java.beans.Introspector to find the properties. Introspector determines the
property names by manipulating the getter and setter method names which
should follow standard Java naming conventions to get the actual property
field name. So for example if there is a method called getFred(), then that
should mean the bean has a field called fred. The AXIS BeanDeserializer
then uses this name when trying to deserialise an XML element.
The problem occurs when XML elements are defined with names starting with a
capital letter. For example the complexsoap sample uses the Zip2Geo.wsdl
which specifies the LatLongReturn complex type with an element called
ServiceError. The Java class generated by WSDL2Java from this has a field
called serviceError and methods isServiceError and setServiceError, so the
BeanDeserialiser propertyMap populated by the Introspector will have a
BeanPropertyDescriptor with the name serviceError with a lowercase 's'. But
the incoming SOAP message needing deserialising will use the name
ServiceError with an uppercase 'S' as specified in the WSDL.
At line 217 in the BeanDeserializer class the following code looks up the
property with the name from the XML Element which has the uppercase 1st
character and will fail to find the BeanPropertyDescriptor:
// look for a field by this name.
propDesc = (BeanPropertyDescriptor) propertyMap.get(localName);
Something like the following code added immediately after the above line
fixes the problem:
if (propDesc == null) {
char[] ca = localName.toCharArray();
ca[0] = Character.toLowerCase(ca[0]);
String ln = ca.toString();
propDesc = (BeanPropertyDescriptor) propertyMap.get(ln);
}
This only causes a problem with beans that don't have the AXIS specific
methods which the BeanDeserialiser will use instead of the Introspector.
The WSIF AddressBook sample names start with lowercase characters so work
ok.
Owen's going to post this to axis-dev to see what the AXIS people think
about changing the BeanDeserialiser, otherwise we'll have to write our own
WSIF specific one which we may need to do anyway depending on how long till
the next AXIS release goes final. Watch axis-dev for progress.
...ant
Anthony Elder
[EMAIL PROTECTED]
Web Services Development
IBM UK Laboratories, Hursley Park
(+44) 01962 818320, x248320, MP208.
"Jacques-Olivier Goussard" <[EMAIL PROTECTED]> on 07/01/2003 20:06:09
Please respond to [EMAIL PROTECTED]
To: <[EMAIL PROTECTED]>
cc:
Subject: RE: wsif - complex type/java bean mapping
Thanks.
Seems a pretty serious problem.
One related question though. As per Ant remarks, I took a look to
test/addressbook/AddressBookTest.java and indeed the Address
class used as return type does not use the AXIS serialization
stuff.
How come this is working ? Is it something in the test setup
(the build/samples path in front of the test/ path in the
classpath for ex.) ?
Jacques-Olivier
-----Original Message-----
From: Nirmal Mukhi [mailto:[EMAIL PROTECTED]]
Sent: Tuesday, January 07, 2003 2:14 PM
To: [EMAIL PROTECTED]
Subject: RE: wsif - complex type/java bean mapping
Hello Jacques,
You are right. We'll look into this problem and see what can be done. Keep
monitoring this list for a response.
Thanks,
Nirmal.
"Jacques-Olivier Goussard" <[EMAIL PROTECTED]>
01/07/2003 02:03 PM
Please respond to axis-user
To: <[EMAIL PROTECTED]>
cc:
Subject: RE: wsif - complex type/java bean mapping
Thanks for quick response.
I made a bit of progress on that problem:
> Its a bit misleading if the samples contain the AXIS
> serialization routines
> as they are not used by WSIF. The AXIS WSDL2Java utility is used to
Well, it does not seem obvious to me. Taking a look at
wsif/providers/soap/apacheaxis/WSIFOperation_ApacheAxis.java,
the method deserialiseResponseObject() will instanciate AXIS
BeanDeserializerFactory based on the WSIFTypeMapping. In that case,
AXIS seems to rely on an existing
public TypeDesc getTypeDesc()
(or alternatively a Deserializer getDeserializer())
method implemented in the bean class itself.
To make sure of this, just comment out the
LatLongReturn#getTypeDesc and LatLongReturn#getDeserializer
methods and run the complexsoap sample to experience the problem.
> To map a complex type to a Java class you use the
> org.apache.wsif.WSIFService class mapType method. For example:
That's what the complexsoap example is doing.
I would have expected WSIF not to be AXIS dependant for the complex
type mapping, as it makes the client code dependant upon the chosen
binding. From the code - but I'm really new to WSIF so there may be
better ways - it seemed to me that the AXIS provider would have to
generate the TypeDesc at runtime (i.e., doing WSDL2Java job) and
use it to create the proper BeanDeserializers.
Thanks
Jacques-Olivier
> -----Original Message-----
> From: Anthony Elder [mailto:[EMAIL PROTECTED]]
> Sent: Tuesday, January 07, 2003 1:50 PM
> To: [EMAIL PROTECTED]
> Subject: Re: wsif - complex type/java bean mapping
>
>
>
> Its a bit misleading if the samples contain the AXIS
> serialization routines
> as they are not used by WSIF. The AXIS WSDL2Java utility is used to
> generate the classes so they have the methods by default, but
> they could be
> deleted and everything should still work.
>
> To map a complex type to a Java class you use the
> org.apache.wsif.WSIFService class mapType method. For example:
>
> service.mapType(
> new javax.xml.namespace.QName(
> "http://wsiftypes.addressbook/",
> "address"),
> Class.forName("addressbook.wsiftypes.Address"));
>
> Or see the doitDyn method in this testcase for a complete example:
> http://cvs.apache.org/viewcvs.cgi/*checkout*/xml-axis-wsif/jav
a/test/addressbook/AddressBookTest.java
And the Address class it uses at:
http://cvs.apache.org/viewcvs.cgi/*checkout*/xml-axis-wsif/java/test/addressbook/wsiftypes/Address.java
When using the WSIFDynamicProxy for stub based invocation WSIF tries to
find a class using the JAX-RPC rules for converting a QName to a Java
class name. So in the above testcase the doit method uses stub invocation
and does not need a mapType call as WSIF can find the
addressbook.wsiftypes.Address class itself. If the class name doesn't match
the QName you can still use mapType calls and stub invocation.
...ant
Anthony Elder
[EMAIL PROTECTED]
Web Services Development
IBM UK Laboratories, Hursley Park
(+44) 01962 818320, x248320, MP208.
"Jacques-Olivier Goussard" <[EMAIL PROTECTED]> on 07/01/2003 14:20:32
Please respond to [EMAIL PROTECTED]
To: <[EMAIL PROTECTED]>
cc:
Subject: wsif - complex type/java bean mapping
Hi
I'm trying to build a generic webservice client that
can handle complex types and is runtime configurable.
Ideally, I wouldn't want users to have to provide a stub
for their complex types.
The WSIF documentation seems to indicate that any well
behaved bean can be used to map complex types on the client
side, but all the examples use WSDL2Java stubs, that contain
AXIS deserialization routines. So
1 - Is there a way to map complex types to a simple bean (no
AXIS getSerializer/getDesrializer routines)?
2 - If not, how can I register at runtime bean deserializers
for AXIS from the WSIF interface ?
Thanks
Jacques-Olivier