I'm getting a class cast
exception on the return value of my service call (both server & client
generated using wsdl2java)
public
java.lang.String _import(com.fcg.dmsl.fdk.services.common.WebServiceValueObject
properties, javax.activation.DataHandler theDocument) throws
java.rmi.RemoteException {
...
setRequestHeaders(_call);
setAttachments(_call);
setAttachments(_call);
// ***
This should be a java.lang.String. Instead, its an instance of the same
typed as the 1st argument
(properties)
java.lang.Object _resp = _call.invoke(new java.lang.Object[] {properties, theDocument});
java.lang.Object _resp = _call.invoke(new java.lang.Object[] {properties, theDocument});
if (_resp
instanceof java.rmi.RemoteException)
{
throw (java.rmi.RemoteException)_resp;
}
else {
extractAttachments(_call);
try {
return (java.lang.String) _resp;
} catch (java.lang.Exception _exception) {
throw (java.rmi.RemoteException)_resp;
}
else {
extractAttachments(_call);
try {
return (java.lang.String) _resp;
} catch (java.lang.Exception _exception) {
// *** Which eventually causes the
ClassCastException
here
return (java.lang.String) org.apache.axis.utils.JavaUtils.convert(_resp, java.lang.String.class);
}
}
return (java.lang.String) org.apache.axis.utils.JavaUtils.convert(_resp, java.lang.String.class);
}
}
I
think I traced this down to the following code in
package org.apache.axis.message;
...
...
public
class BodyBuilder extends SOAPHandler
...
...
public SOAPHandler onStartChild(String
namespace,
String localName,
String prefix,
Attributes attributes,
DeserializationContext context)
...
String localName,
String prefix,
Attributes attributes,
DeserializationContext context)
...
// Only deserialize this way if there is a unique
operation
// for this QName. If there are overloads,
// we'll need to start recording. If we're making a high-
// fidelity recording anyway, don't bother (for now).
if (msgContext != null && !msgContext.isHighFidelity() &&
(operations == null || operations.length == 1)) {
((RPCElement)element).setNeedDeser(false);
handler = new RPCHandler((RPCElement)element, false); // *** Hard coded false seems wrong to me
if (operations != null) {
((RPCHandler)handler).setOperation(operations[0]);
msgContext.setOperation(operations[0]);
}
}
// for this QName. If there are overloads,
// we'll need to start recording. If we're making a high-
// fidelity recording anyway, don't bother (for now).
if (msgContext != null && !msgContext.isHighFidelity() &&
(operations == null || operations.length == 1)) {
((RPCElement)element).setNeedDeser(false);
handler = new RPCHandler((RPCElement)element, false); // *** Hard coded false seems wrong to me
if (operations != null) {
((RPCHandler)handler).setOperation(operations[0]);
msgContext.setOperation(operations[0]);
}
}
The
2nd argument to the RPCHandler() constructor is named
"isResponse"
public RPCHandler(RPCElement rpcElem, boolean
isResponse)
It
seems wrong to me that this should be hard-coded to false. It appears that
this code is (also) used when deserializing the response from the server.
Since the RPCHandler class uses the "isResponse" flag to determine what the type
should be, this explains why my Axis client code is incorrectly thinking the
return value is the same type as my first request
parameter.
Also, the test for
msgContext.isHighFidelity() explains why streaming needs to be in effect for
this issue to arise.
As a quick test, I
changed this to "true", and my Axis client application worked fine.
However, this can't be the right fix, since I suppose that this same code is
used to deserialize the request message on the server side.
I noted that the one
other call to the RPCHandler constructor determined the value of isResponse as
follows.
boolean isResponse = ((msg !=
null)
&&
Message.RESPONSE.equals(msg.getMessageType()));
Message.RESPONSE.equals(msg.getMessageType()));
// We're going to need this
below, so create one.
RPCHandler rpcHandler = new RPCHandler(this, isResponse);
RPCHandler rpcHandler = new RPCHandler(this, isResponse);
Hopefully, this is coherent.
Regards,
Jeremy
