After stepping through the Axis source, I found the solution to my problem. And I think I found a bug. Or 3 bugs. I'm not sure which. OperationDesc.getOutputParamByQName(QName) calls ParameterDesc.getQName(). But ParameterDesc.getQName() returns the variable "name". For my object, "name" was "CustomerFinancial" and its typeQName was "{urn:uOBI_Intf}TCustomerFinancial" and therefore didn't match.
I question that ParameterDesc.getQName() is returning 'name'. That's one potential bug. Or perhaps OperationDesc.getOutputParamByQName(QName) should call pnext.getTypeQName() instead. That's a 2nd potential bug. I solved my problem by correcting the incorrect addParameter() calls in my stub that was created by WSDL2Java, which could be considered the third bug. oper.addParameter(new javax.xml.namespace.QName("", "CustomerFinancial"), new javax.xml.namespace.QName("urn:uOBI_Intf", "TCustomerFinancial"), com.ncube.vod.bps.billing.obi.TCustomerFinancial.class, org.apache.axis.description.ParameterDesc.INOUT, false, false); had to become oper.addParameter(new javax.xml.namespace.QName("urn:uOBI_Intf", "TCustomerFinancial"), new javax.xml.namespace.QName("urn:uOBI_Intf", "TCustomerFinancial"), com.ncube.vod.bps.billing.obi.TCustomerFinancial.class, org.apache.axis.description.ParameterDesc.INOUT, false, false); The specific characteristics of this is that the call returned an object and had an INOUT parameter. The return was handled correctly, but the destClass and deserializer was defaulted to the return type when the name could not be matched up.