Hi all,
I'm working with Tomcat 4, Axis beta 3, JDK 1.3.1_04, all on Windows 2K.
We're developing a RPC-style web service by deploying our own deploy.wsdd,
so we're not using the WSDLJava tools. We have our own classes that we've
written serializers for and they mostly work without a problem, but we are
having problems with a particular piece.
Here's the details: We've got a User and a Role classes. Each of these has
Axis Serializers, Deserializers, and the respective Factories. The User
class can have a Set of Roles as a member variable and the Role has a single
user as a member variable.
Retrieving a single Role class with a populated User member variable with no
Set of Roles defined works fine, both the Role and it's User class are
mashalled correctly. But retrieving a User with a Set of Roles is failing
and we need help figuring out what to do. A null is returned from the
call.invoke method instead of an instantiated User object.
The XML returned from the server looks good to me, but then I've only been
working with SOAP for the last couple weeks:) It looks to me like the
UserDeserializer's 'value' object is being populated correctly, but isn't
getting matched up somewhere. The Set of Roles in the User is converted to
a Vector in the SOAP message in the UserSerializer.
Below is the (hopefully) relevant code of our UserDeserializer, the XML
returned by the getUser service call, and the relevant DEBUG output from
Axis during it's client run (from the deserializer's onEndElement() to the
end of the program).
Of note in the DEBUG output is that JavaUtils.convert(arg, destClass)
outputs the line "Trying to convert null to com.infonow.oms.session.User",
which doesn't seem right to me.
Any help with this would be greatly appreciated.
Thanks,
Chris
UserDeserializer:
/**
* This method is invoked when an element start tag is encountered.
*
* @param namespace is the namespace of the element
* @param localName is the name of the element
* @param prefix is the element's prefix
* @param attributes are the attributes on the element...used to get the
type
* @param context is the DeserializationContext
*/
public SOAPHandler onStartChild(String namespace,
String localName,
String prefix,
Attributes attributes,
DeserializationContext context)
throws SAXException
{
QName typeQName = (QName)typesByMemberName.get(localName);
if (typeQName == null)
throw new SAXException("Invalid element in User struct - " +
localName);
// These can come in either order.
Deserializer dSer = context.getDeserializerForType(typeQName);
if (dSer == null)
throw new SAXException("No deserializer for a " + typeQName
+ "???");
DeserializerTarget dt = new DeserializerTarget(this, localName);
if (dt != null) {
dSer.registerValueTarget(dt);
}
return (SOAPHandler)dSer;
}
/**
* This method is invoked as the target of each child element
deserialization.
*
* @param value is the child object created by the deserialization
* @param hint is the key specified by the target. In this case, it's
the localname of the child element.
*/
public void setValue(Object value, Object hint) {
userAttributes.put(hint.toString(), value);
}
/**
* This method is invoked when the end element of the User object is hit
in the SOAP message.
*
* @param namespace is the namespace of the element
* @param localName is the name of the element
* @param context is the DeserializationContext
*/
public void onEndElement(java.lang.String namespace, java.lang.String
localName,
DeserializationContext context) throws org.xml.sax.SAXException
{
// User constructor with ID
value = new User(new ID((String)userAttributes.get(IDMEMBER)));
// User locale
((User)value).setLocale(Util.parseLocale((String)userAttributes.get(LOCALEME
MBER)));
// User role set
Vector roles = (Vector) userAttributes.get(ROLESMEMBER);
for (Enumeration e = roles.elements(); e.hasMoreElements(); ) {
Role role = (Role) e.nextElement();
log.debug("onEndElement() : role ID "+role.getID());
role.setUser((User)value);
((User)value).getRoles().add(role);
}
// User username/password map
HashMap userPassMap = (HashMap)
userAttributes.get(USERNAMESMEMBER);
for (Iterator i = userPassMap.keySet().iterator();
i.hasNext(); ) {
String username = (String) i.next();
((User)value).addUsername(username, (String)
userPassMap.get(username));
}
log.debug("onEndElement() : User ID at end of deser
"+((User)value).getID());
if (value == null)
log.debug("onEndElement() : value is null");
}
Response from service for getUser() call:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<ns1:getUserResponse
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:ns1="OMSFacade">
<getUserReturn href="#id0"/>
</ns1:getUserResponse>
<multiRef id="id0" soapenc:root="0"
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xsi:type="ns2:User"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:ns2="urn:OMSService">
<idMember xsi:type="xsd:string">X46-1030463248-c7ef0bd4</idMember>
<localeMember xsi:type="xsd:string">en_US</localeMember>
<rolesMember href="#id1"/>
<usernamesMember href="#id2"/>
</multiRef>
<multiRef id="id2" soapenc:root="0"
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xsi:type="ns3:Map" xmlns:ns3="http://xml.apache.org/xml-soap"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
<item>
<key xsi:type="xsd:string">topher</key>
<value xsi:type="xsd:string">secret</value>
</item>
</multiRef>
<multiRef id="id1" soapenc:root="0"
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xsi:type="ns4:Vector" xmlns:ns4="http://xml.apache.org/xml-soap"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
<item href="#id3"/>
</multiRef>
<multiRef id="id3" soapenc:root="0"
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xsi:type="ns5:Role" xmlns:ns5="urn:OMSService"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
<idMember xsi:type="xsd:string">X47-1030463248-c7ef0bd4</idMember>
<userMember href="#id0"/>
</multiRef>
</soapenv:Body>
</soapenv:Envelope>
DEBUG output from UserDeserializer.onEndElement to end of program:
- onEndElement() : role ID X47-1030463248-c7ef0bd4
- onEndElement() : User ID at end of deser X46-1030463248-c7ef0bd4
- Put of deserialized value= com.infonow.oms.session.User@4ac6db for id= id0
- Popped element stack to null
- Exit: DeserializationContextImpl::endElement()
- NSPush (34)
- Exit: DeserializationContextImpl::startElement()
- Enter: DeserializationContextImpl::endElement(, getUserReturn)
- Popping handler org.apache.axis.message.EnvelopeHandler@456c60
- Popped element stack to null
- Exit: DeserializationContextImpl::endElement()
- Enter: DeserializationContextImpl::endElement(OMSFacade, getUserResponse)
- Popping handler org.apache.axis.message.RPCHandler@659128
- Setting MessageContext property in RPCHandler.endElement().
- Popped element stack to null
- Exit: DeserializationContextImpl::endElement()
- Exit: Call::invoke(RPCElement)
- Trying to convert null to com.infonow.oms.session.User
- Exit: Call::invoke(ns, meth, args)
- axis.Call.invoke: 601 {OMSFacade}getUser
java.lang.RuntimeException: FacadeAxisClient.getUser() : null returned from
server
java.lang.RuntimeException: Null user
at com.infonow.oms.facade.Main.go(Main.java:45)
at com.infonow.oms.facade.Main.main(Main.java:19)
Exception in thread "main"
|