Skip to main content

Web services programming tips and tricks: Exception Handling with JAX-RPC

Throw the right exception from the service endpoint

Ping Wang, Software Engineer, IBM, Software Group
Ping Wang is one of the developers of the IBM WebSphere Web services engine. Previously, he was a developer for WebSphere System Management and focused on how to manage distributed processes using JMX (Java Management eXtension). You can contact Ping at pacific at us.ibm.com
Russell Butek (butek@us.ibm.com), Software Engineer, IBM, Software Group
Russell Butek is one of the developers of the IBM WebSphere Web services engine. He is also an IBM representative on the JAX-RPC Java Specification Request (JSR) expert group. He was involved in the implementation of Apache's AXIS SOAP engine, driving AXIS 1.0 to comply with JAX-RPC 1.0. Previously, he was a developer of the IBM CORBA ORB and an IBM representative on a number of OMG task forces: the portable interceptor task force (of which he was chair), the core task force, and the interoperability task force. You can contact Russell at butek at us.ibm.com.

Summary:  Explicitly declaring faults in WSDL operations, like explicitly declaring exceptions in Java methods, is good programming practice. This tip first examines the exception behavior in the absence of wsdl:fault. It then focuses on how a wsdl:fault is mapped to a checked Java exception and how a JAX-RPC runtime handles this checked exception.

Date:  06 Feb 2004
Level:  Introductory
Activity:  15315 views

In the SOAP Web services world, a fault flows from the server to the client in the form of SOAP fault. A SOAP fault consists of the faultcode, faultstring, and optional fault actor and detail. The JAX-RPC specification defines various rules about how to map from a Java exception to a SOAP fault (server side) and from the SOAP fault back to the Java exception (client side).

There are four types of exceptions that can be thrown from the server.

  • java.rmi.RemoteException
  • java.lang.RuntimeException
  • javax.xml.rpc.soap.SOAPFaultException (a special, subclass of RuntimeException)
  • a checked, user-defined exception (mapped from the WSDL's wsdl:fault construct)

The client side will receive one of the following types of exceptions. Note that the client can not catch any RuntimeException other than SOAPFaultException.

  • java.rmi.RemoteException
  • javax.xml.rpc.soap.SOAPFaultException
  • a checked, user-defined exception

This article first discusses the expected behaviour on the client when the server throws various exceptions, and then emphasizes the use of checked exceptions.

RemoteException

JAX-RPC requires that all remote methods in a service endpoint interface (SEI) throw the standard java.rmi.RemoteException. This allows exceptions which arise from communications or runtime difficulties to propagate back to the caller. However, there is no portable means to send specific subclasses of RemoteException.

The application itself could also throw a RemoteException. However, since there is no portable means of sending specific RemoteExceptions, the client cannot catch specific RemoteExceptions. For a given SOAP fault returned from the server, different client-side JAX-RPC runtimes may have different interpretations and generate different RemoteExceptions. Because of this interoperability problem, the application should avoid throwing RemoteExceptions.


RuntimeException

When a problem occurs in a server-side JAX-RPC runtime which results in a RuntimeException being thrown (for example, NullPointerException), that exception will propagate back to the client, but it will do so as a SOAP fault. The client runtime will map SOAP fault to either RemoteException or SOAPFaultException (described below). Therefore, a service endpoint should not throw a RuntimeException expecting the client to always catch that RuntimeException because the client may receive a RemoteException instead.


SOAPFaultException

There is one special RuntimeException: javax.xml.rpc.soap.SOAPFaultException. SOAPFaultException is more descriptive than a RuntimeException and dictates the exact SOAP fault message which flows to the client. In other words, whoever throws this fault, whether the runtime or the application, controls the SOAP fault response. Therefore, how to map the SOAP fault to an appropriate exception really depends on the content of SOAPFaultException, it may be mapped to SOAPFaultException, RemoteException or even a checked user exception. SOAPFaultException is often used by JAX-RPC handlers. A JAX-RPC application itself normally should avoid throwing the SOAPFaultException.


Checked user exception

A good programming practice often involves explicitly defining checked user exceptions as part of the interface contract. In the JAX-RPC world, programmers need to first define wsdl:faults as part of a wsdl:operation. A wsdl:operation allows multiple wsdl:fault elements, just like a Java method allows multiple exceptions. Each wsdl:fault is mapped to a user exception as part of the SEI. In most cases, Java exceptions do not have complicated data structures; similarly for wsdl:fault, the schema definition referenced by the wsdl:fault is often straightforward. Nevertheless, it's still very important for programmers to think over which kind of exceptions are expected to be thrown, and then define appropriate wsdl:faults.

Mapping rules

Unlike wsdl:input and wsdl:output, the message referenced by wsdl:fault is only allowed a single message part which could refer to a simple type or a complex type. If the part element has a type attribute, then you can tell directly whether the type is simple (for example, xsd:int, xsd:string, etc.) or complex. If the part element has an element attribute, then you have to step to the element to see whether the type is simple or complex.

Mapping rules for simple types


For a simple type, the Java exception name is mapped from the name attribute of the wsdl:message element. The wsdl:part name is mapped to a getter method and a parameter in the constructor of the Java exception. For example, the fault information in the WSDL in Listing 1 maps to the Java language exception in Listing 2.


Listing 1. WSDL definition with a simple fault
<definitions ...>

  <message name="empty"/>
  <message name="InsufficientFundsFault">
    <part name="balance" type="xsd:int"/>
  </message>

  <portType name="Bank">
    <operation name="throwException">
      <input message="tns:empty"/>
      <output message="tns:empty"/>
      <fault name="fault" message="tns:InsufficientFundFault"/>
    </operation>
  </portType>
  ...
</definitions>


Listing 2. Java exception from the fault in Listing 1
public class InsufficientFundFault extends java.lang.Exception {
    private int balance;
    public int getBalance() {
        return this.balance;
    }

    public InsufficientFundFault() {
    }

    public InsufficientFundFault(int balance) {
        this.balance = balance;
    }
}

Mapping rules for complex types


For complexTypes, the Java exception name is mapped from the name of the complexType (or the name of the element if the fault message's part refers to an element). Each element inside the complexType is mapped to a parameter in the constructor of the Java exception and a getter method. Note that, unlike beans, there is no setter method. The only way to set such a field is through the exception constructor. For example, the fault information in the WSDL in Listing 3 maps to the Java language exception in Listing 4.


Listing 3. WSDL definition for a complex fault
<definitions ...>

  <types>
    <schema xmlns="http://www.w3.org/2001/XMLSchema">
      <element name="InsufficientFundFault">
        <complexType>
          <sequence>
            <element name="balance" type="xsd:int"/>
            <element name="requestedFund" type="xsd:int"/>
          </sequence>
        </complexType>
      </element>
    </schema>
  </types>
			 
  <message name="empty"/>
  <message name="withdrawRequest">
    <part name="amount" type="xsd:int"/>
  </message>
  <message name="InsufficientFundFaultMessage">
    <part name="fault" element="tns:InsufficientFundFault"/>
  </message>

  <portType name="Bank">
    <operation name="withdraw">
      <input message="tns:withdrawRequest"/>
      <output message="tns:empty"/>
      <fault name="fault" message="tns:InsufficientFundFaultMessage"/>
    </operation>
  </portType>

  ...
</definitions>


Listing 4: Java exception from the fault in Listing 3
    public class InsufficientFundFault 
    	extends java.lang.Exception 
    	implements java.io.Serializable {
    private int balance;
    private int requestedFund;

    public InsufficientFundFault(
           int balance,
           int requestedFund) {
        this.balance = balance;
        this.requestedFund = requestedFund;
    }

    public int getBalance() {
        return balance;
    }

    public int getRequestedFund() {
        return requestedFund;
    }
}

Mapping rules for fault inheritance


Suppose you want to define a subclass of InsufficientFundFault, called AccountInsufficientFundFault, to carry the account number of the requesting client (see Listing 5). Your application can throw this subclass exception and your client would receive this exception. Very straightforward.


Listing 5: WSDL faults with inheritance
  <wsdl ...>
    <types>
    <schema targetNamespace="http://example" ...>
      ...

      <complexType name="InsufficientFundFaultType">
        <sequence>
          <element name="balance" type="xsd:int"/>
          <element name="requestedFund" type="xsd:int"/>
        </sequence>
      </complexType>

      <complexType name="AccountInsufficientFundFaultType">
        <complexContent>
           <extension base="tns:InsufficientFundFaultType">
             <sequence>
               <element name="account" type="xsd:string"/>
             </sequence>
           </extension>
        </complexContent>
      </complexType> 
			     		    
      <element name="InsufficientFundFault" 
               type="tns:InsufficientFundFaultType"/>
      ...
    </schema>
    </types>
			 
    <message name="AccountInsufficientFundFaultMessage">
      <part element="tns:AccountInsufficientFundFault" name="fault"/>
    </message>
			
    <operation name="withdraw">
      <input message="tns:withdrawRequest" name="withdrawRequest"/>
      <output message="tns:withdrawResponse" name="withdrawResponse"/>
      <fault message="tns:InsufficientFundFaultMessage" 
                name="InsufficientFundFault"/>
    </operation>
    ...
  </wsdl>
  

By doing this, the method "withdraw" of the generated SEI stays the same (see Listing 6). One item to note, however, is that any subclass of InsufficientFundFault must appear in the WSDL file for the client to receive that exception. You cannot create a new subclass of InsufficientFundFault in the server-side Java component without doing the same in the WSDL file. WSDL is a declarative language. Every possible fault that a service can throw must be explicitly defined in the XML, otherwise the client will not know about it and will not be able to receive it.


Listing 6: Java SEI mapped from the above WSDL definition
  public interface Bank extends java.rmi.Remote {
    public boolean withdraw(java.lang.String account, int amount) 
        throws java.rmi.RemoteException, 
               example.InsufficientFundFaultType;
  }

SOAP fault content

The JAX-RPC runtime catches a user exception and serializes it to XML data based on the schema definition referenced by the message part of the wsdl:fault. Such XML data is used to fill in the content of the detail element of the SOAP fault. Listing 7 is the SOAP message for the complex InsufficientFundFault example. The SOAP message for a simpleType fault is similar except that the detail section is different.


Listing 7: SOAP Fault example
  <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Body>
      <soapenv:Fault>
        <faultcode >...</faultcode>
        <faultstring>...</faultstring>
        <detail>
          <InsufficientFundFault xmlns="http://example">
            <balance>1000</balance>
            <requestedFund>2000</requestedFund>
          </InsufficientFundFault>
        </detail>
      </soapenv:Fault>
    </soapenv:Body>
  </soapenv:Envelope>
  

The key thing here is that the detail section carries the content which must match the schema definition referenced by wsdl:fault. In this way, the client runtime will know which user exception it should be mapped to. Also note that the SOAP fault does not carry the exception stack trace as you normally expect for the Java exception; therefore, a Web services client should not expect to see the stack trace originating from the server side.


Summary

It is good programming practice to introduce user-defined faults. Using RemoteExceptions or RuntimeExceptions is not only too general, there is also no guarantee that every vendor will handle these in the same manner.

Once you decide to introduce user-defined faults, you must decide what kinds of faults to use -- faults of simple types, faults of complexTypes, or an inheritance tree of faults -- and you must understand how those faults map to Java programming artifacts.



Download

DescriptionNameSizeDownload method
Source code for this articlews-tip-jacrpc.zip40KB HTTP

Information about download methods


Resources

About the authors

Ping Wang is one of the developers of the IBM WebSphere Web services engine. Previously, he was a developer for WebSphere System Management and focused on how to manage distributed processes using JMX (Java Management eXtension). You can contact Ping at pacific at us.ibm.com

Russell Butek is one of the developers of the IBM WebSphere Web services engine. He is also an IBM representative on the JAX-RPC Java Specification Request (JSR) expert group. He was involved in the implementation of Apache's AXIS SOAP engine, driving AXIS 1.0 to comply with JAX-RPC 1.0. Previously, he was a developer of the IBM CORBA ORB and an IBM representative on a number of OMG task forces: the portable interceptor task force (of which he was chair), the core task force, and the interoperability task force. You can contact Russell at butek at us.ibm.com.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=SOA and Web services, XML
ArticleID=11880
ArticleTitle=Web services programming tips and tricks: Exception Handling with JAX-RPC
publish-date=02062004
author1-email=pacific@us.ibm.com
author1-email-cc=
author2-email=butek@us.ibm.com
author2-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Special offers