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.

Reply via email to