You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-dev@axis.apache.org by "Shellman, Joel" <Jo...@summit.fiserv.com> on 2003/05/01 01:45:28 UTC

RE: exception and SOAP fault

I'm trying to use your patch but:

>         if (context.getTypeMapping().getSerializer(detailObject.getClass())!=null) {

Always fails for my Exception. How do I make sure that it will find my class?

I thought having a beanMapping in server-config.wsdd:

  <beanMapping qname="myNS:ServiceException" xmlns:myNS="urn:services.summitsite.com"
       languageSpecificType="java:com.summitsite.services.ServiceException"/>

But it's not working.

-joel

-----Original Message-----
From: David Green 
Sent: Wednesday, April 30, 2003 1:34 PM
To: axis-user@ws.apache.org
Cc: axis-dev@xml.apache.org
Subject: RE: exception and SOAP fault


I've confirmed that:

	1. I can throw any exception inheriting from java.lang.Exception and have a SOAP fault with data and exception class providing that a serializer/deserializer are registered for the class of the exception.
	2. Previous behaviour is maintained for exceptions that don't inherit from AxisFault, and for which there is no serializer registered.
	3. Previous behaviour for exceptions inheriting from AxisFault is maintained.

This means that no axis-specific code is required in my JAX-RPC service implementation.

It seems like what I produced previously is actually not enough.  After some testing, the following patch seems to be working. Any feedback would be welcome.  


Index: java/src/org/apache/axis/AxisFault.java
===================================================================
RCS file: /home/cvspublic/xml-axis/java/src/org/apache/axis/AxisFault.java,v
retrieving revision 1.74
diff -r1.74 AxisFault.java
108c108
< 
---
>     
258c258
<         }
---
>         }        
267a268
>         boolean haveTypeDetailMapping = false;
271c272,288
<             addFaultDetail(Constants.QNAME_FAULTDETAIL_EXCEPTIONNAME,
---
>           haveTypeDetailMapping = true;
>         }
>         if (!haveTypeDetailMapping) {
>           MessageContext context = MessageContext.getCurrentContext();
>           if (context != null) {
>             try {
>               if (context.getTypeMapping().getSerializer(target.getClass()) != null) {
>                 haveTypeDetailMapping = true;
>               }
>             } catch (Exception e) {
>               // swallow this exception, since we're just trying to 
>               // determine if we have a serializer.
>             }
>           }
>         }
>         if (haveTypeDetailMapping) {          
>           addFaultDetail(Constants.QNAME_FAULTDETAIL_EXCEPTIONNAME,
273a291
>         
750a769
>     
756c775,788
<         // no data in default Axis fault
---
>       Object detailObject = (getCause()==null)?this:getCause();
>       boolean haveSerializer = false;
>       
>       try {
>         if (context.getTypeMapping().getSerializer(detailObject.getClass())!=null) {
>           haveSerializer = true;
>         }
>       } catch (Exception e) {
>         // swallow this exception, it means that we don't know how to serialize
>         // the details.
>       }
>       if (haveSerializer) {        
>         context.serialize(qname, null, detailObject);
>       }


-----Original Message-----
From: David Green 
Sent: Wednesday, April 30, 2003 11:43 AM
To: 'axis-user@ws.apache.org'
Cc: 'axis-dev@xml.apache.org'
Subject: RE: exception and SOAP fault


The following patch to AxisFault ensures that any exception that has a serializer registered will serialize the exception details to the SOAP fault without having to have the exception class extend AxisFault:

Index: java/src/org/apache/axis/AxisFault.java
===================================================================
RCS file: /home/cvspublic/xml-axis/java/src/org/apache/axis/AxisFault.java,v
retrieving revision 1.74
diff -r1.74 AxisFault.java
756c756,768
<         // no data in default Axis fault
---
>       Object detailObject = (getCause()==null)?this:getCause();
>       boolean haveSerializer = false;
>       try {
>         if (context.getTypeMapping().getSerializer(getClass())!=null) {
>           haveSerializer = true;
>         }
>       } catch (Exception e) {
>         // swallow this exception, it means that we don't know how to serialize
>         // the details.
>       }
>       if (haveSerializer) {        
>         context.serialize(qname, null, detailObject);
>       }

I apologize for the cross-post.  It's not clear to me which list should be used for contributions.

David

-----Original Message-----
From: David Green 
Sent: Wednesday, April 30, 2003 11:00 AM
To: axis-user@ws.apache.org
Subject: RE: exception and SOAP fault


Thomas,

Thankyou -- it works.  From what I can tell, all that is needed for faults with data to work with any exception (not just exceptions that extend AxisFault) is for the following method to be implemented in AxisFault:


    /**
     *  Writes any exception data to the faultDetails
     * This is for overriding; it is empty in the base AxisFault
     */
    public void writeDetails(QName qname, SerializationContext context) throws java.io.IOException {
        // no data in default Axis fault
    }

As you can see, the current implementation does nothing.  It seems that the only reason we get the fault data with the WSDL2Java generated exception is due to the generated code overriding this method as follows:

    /**
     * Writes the exception data to the faultDetails
     */
    public void writeDetails(javax.xml.namespace.QName qname, org.apache.axis.encoding.SerializationContext context) throws 	java.io.IOException {
        context.serialize(qname, null, this);
    }

Perhaps it's too simplistic, but it seems that a reasonable modification to AxisFault would solve the problem.  All that would be needed is the following:

1. AxisFault.initFromException() would save the instance of the exception in a member variable. 2. AxisFault.writeDetails() would be implemented as follows:


    /**
     *  Writes any exception data to the faultDetails
     * This is for overriding; it is empty in the base AxisFault
     */
    public void writeDetails(QName qname, SerializationContext context) throws java.io.IOException {
      if (exceptionDetail != null) { // <----- this is the exception that was saved in initFromException()
        context.serialize(qname, null, exceptionDetail);
      }
    }

In any case, it's possible that I've missed something.  Is there some reason why this wasn't done already?  In any case, I'm going to try it here to see if there are any other side effects of doing this.

David


-----Original Message-----
From: David Green 
Sent: Wednesday, April 30, 2003 9:43 AM
To: axis-user@ws.apache.org
Subject: RE: exception and SOAP fault


Thomas,

Thankyou very much for your help.  I'll give it a try and let you know how it goes.

It's a shame that we must use axis-specific code in our exceptions on the server to make it work.

David

-----Original Message-----
From: Thomas.Rothfuss @ .de []
Sent: Tuesday, April 29, 2003 9:48 PM
To: axis-user@ws.apache.org
Subject: Re: exception and SOAP fault



Hi David,

I started with the WSDL file and created the java classes by using WSDL2Java.

The exception class itself is derived from AxisFault:
    public class WoodCommanderException  extends org.apache.axis.AxisFault implements java.io.Serializable

The method throwing the exception is declared like this:
    public Homag.WoodCommander.Soap.Value getValue(java.lang.String in0) throws java.rmi.RemoteException, Homag.WoodCommander.Soap.WoodCommanderException

In your case the BusinessException extends the TestException. Perhaps this may be a problem in Axis. I never tried that.

I already posted my scenario in this mailing list. Here is the pointer:
    http://marc.theaimsgroup.com/?l=axis-user&m=104988960618062&w=2

Hope this will help

Thomas



|---------+---------------------------------->
|         |           "David Green"          |
|         |           <david.green@maketechno|
|         |           logies.com>            |
|         |                                  |
|         |                                  |
|         |                                  |
|         |           30.04.03 03:01         |
|         |           Bitte antworten an     |
|         |           axis-user              |
|         |                                  |
|---------+---------------------------------->
  >------------------------------------------------------------------------------------------------------------------------------|
  |                                                                                                                              |
  |       An:       <ax...@xml.apache.org>                                                                                   |
  |       Kopie:                                                                                                                 |
  |       Thema:    exception and SOAP fault                                                                                     |
  >------------------------------------------------------------------------------------------------------------------------------|



I've been attempting to find documentation on how to have SOAP faults created from custom exception types on the server, and re-thrown on the client.

There appear to be several threads on this, none of which have enough information for me to produce the desired result.  If there is known documentation on this, can someone please direct me to it?  Otherwise, does anyone know how to do this?

Desired behavior:

1. Declare a Java class on the server with methods that throw the appropriate exception type (that preferably inherits from java.lang.Exception, not AxisFault) 2. Declare the exception class with appropriate get/set methods for all properties. 3. Whenever necessary, on the server throw an instance of the exception. 4. If necessary configure (using the wsdd file) serializers for the exception class. 5. If thrown, Axis on the server creates a SOAP fault with sufficient data that the exception can be re-created on the client side. 6. Generated WSDL contains accurate fault definitions.

So far I've been able to do all of the above except for 5.  The WSDL appears to be correct, however the fault contains none of the relevant data.  If the exception class inherits from AxisFault, the fault appears as
follows:

<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>
  <soapenv:Fault>
   <faultcode>soapenv:Server.generalException</faultcode>
   <faultstring>Internal server error. (ref# 10301)</faultstring>
   <detail>
    <ns1:exceptionName xmlns:ns1="http://xml.apache.org/axis/
">com.maketechnologies.webservice.test.BusinessException</ns1:exceptionName>

   </detail>
  </soapenv:Fault>
 </soapenv:Body>
</soapenv:Envelope>

This causes the client to properly instantiate the BusinessException, however the BusinessException contains the following information (from
WSDL):

<complexType name="TestException">
  <sequence>
    <element name="message" nillable="true" type="xsd:string" />
  </sequence>
</complexType>
<complexType name="BusinessException">
  <complexContent>
    <extension base="impl:TestException">
      <sequence>
       <element name="errorCode" type="xsd:int" />
      </sequence>
    </extension>
  </complexContent>
</complexType>

As you can see, the errorCode is not transmitted over the wire.

Any help and/or pointers to documentation would be greatly appreciated.

David