DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT <http://nagoya.apache.org/bugzilla/show_bug.cgi?id=22724>. ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND INSERTED IN THE BUG DATABASE.
http://nagoya.apache.org/bugzilla/show_bug.cgi?id=22724 Faults with identically named parts are not always properly deserialized Summary: Faults with identically named parts are not always properly deserialized Product: Axis Version: 1.1 Platform: Other OS/Version: Other Status: NEW Severity: Critical Priority: Other Component: Serialization/Deserialization AssignedTo: [EMAIL PROTECTED] ReportedBy: [EMAIL PROTECTED] The above problem is caused by the way QNames for FaultInfo and FaultDescr objects are formed. The following pieces of code taken from AXIS 1.1 final clarify the issue. SymbolTable.faultsFromSOAPFault: ... ... String soapFaultNamespace = ""; Iterator faultIter = bFault.getExtensibilityElements().iterator(); for (; faultIter.hasNext();) { Object obj = faultIter.next(); if (obj instanceof SOAPFault) { foundSOAPFault = true; soapFaultUse = ((SOAPFault)obj).getUse(); soapFaultNamespace = ((SOAPFault)obj).getNamespaceURI(); // <-- namespaceURI break; } else if (obj instanceof UnknownExtensibilityElement) { ... ... } } ... ... Fault opFault = operation.getFault(bFault.getName()); if (opFault == null) { ... } // put the updated entry back in the map faults.add(new FaultInfo(opFault, Use.getUse(soapFaultUse), soapFaultNamespace, this)); FaultInfo: ... public FaultInfo(Fault fault, Use use, String namespace, SymbolTable symbolTable) { ... ... Part part = getFaultPart(); if (part == null) { this.qName = null; } else if (part.getTypeName() != null) { this.qName = new QName(namespace, part.getName()); // <-- localName } ... } // ctor ... ... public QName getQName() { return qName; } // getQName JavaStubWriter.writeFaultInfo: ... Map faultMap = bEntry.getFaults(); // Get the list of faults for this operation ArrayList faults = (ArrayList) faultMap.get(bindOp); // check for no faults ... // For each fault, register its information for (Iterator faultIt = faults.iterator(); faultIt.hasNext();) { FaultInfo info = (FaultInfo) faultIt.next(); QName qname = info.getQName(); Message message = info.getMessage(); // if no parts in fault, skip it! ... // Get the Exception class name String className = Utils.getFullExceptionName(message, symbolTable); // output the registration API call pw.println(" oper.addFault(new org.apache.axis.description.FaultDesc("); pw.println(" " + Utils.getNewQName(qname) + ","); // <-- the QName value is taken from the corresponding FaultInfo object pw.println(" \"" + className + "\","); pw.println(" " + Utils.getNewQName (info.getXMLType()) + ", "); pw.println(" " + Utils.isFaultComplex(message, symbolTable)); pw.println(" ));"); } FaultDesc: ... ... public FaultDesc(QName qname, String className, QName xmlType, boolean complex) { this.qname = qname; this.className = className; this.xmlType = xmlType; this.complex = complex; } public QName getQName() { return qname; } ... ... As a result, the QName of a FaultInfo as well as the QName of the corrsponding FaultDescr object is a combination of the name of the fault's message part and the value of the fault's namespace attribute, e.g. the QName of a FaultInfo object generated for the following soap fault element would be '{urn:AddressFetcher2}ex'. <wsdl:message name="Exception"> <wsdl:part name="ex" type="typens:addressException"/> </wsdl:message> <wsdl:binding name="name" type="typens:AddressBook"> ... <wsdl:operation name="addEntry"> ... <wsdl:fault name="fa"> <soap:fault name="SoapFault" use="encoded" namespace="urn:AddressFetcher2"/> </wsdl:fault> </wsdl:operation> </wsdl:binding> This poses problems when deserializing faults with code generated by WSDL2Java for documents similar to the one below: <wsdl:message name="Exception"> <wsdl:part name="ex" type="typens:addressException"/> </wsdl:message> <wsdl:message name="Exception1"> <wsdl:part name="ex" type="typens1:addressException1"/> </wsdl:message> <wsdl:binding name="name" type="typens:AddressBook"> ... <wsdl:operation name="addEntry"> ... <wsdl:fault name="fa"> <soap:fault name="SoapFault" use="encoded" namespace="urn:AddressFetcher2"/> </wsdl:fault> <wsdl:fault name="fa1"> <soap:fault name="SoapFault1" use="encoded" namespace="urn:AddressFetcher2"/> </wsdl:fault> </wsdl:operation> </wsdl:binding> Here we will eventually have two FaultDescr objects whose QName's are identical, and the following piece of code from 'SOAPFaultDetailsBuilder.onStartChild' will always find the first FaultDescr object registered for the operation called: MessageContext msgContext = context.getMessageContext(); SOAPConstants soapConstants = msgContext.getSOAPConstants(); OperationDesc op = msgContext.getOperation(); Class faultClass = null; QName faultXmlType = null; if (op != null) { FaultDesc faultDesc = op.getFaultByQName(qn); // <-- finds the first descr. // allow fault type to be denoted in xsi:type if (faultDesc == null) { ... } else { faultXmlType = faultDesc.getXmlType(); } if (faultDesc != null) { // Set the class try { faultClass = ClassUtils.forName(faultDesc.getClassName()); } catch (ClassNotFoundException e) { // Just create an AxisFault, no custom exception } } } else { ... } As a result, on the client side, an exception object of type 'typens:addressException' will be constructed, even though an exception of type 'typens1:addressException1' might have been thrown on the server. We tracked this behaviour down to the changes of dims as of 2003/01/19. Thank you, Andrei.