Skip to main content

Faults and exceptions in JAX-WS

Russell Butek (butek@us.ibm.com), Certified IT Specialist, IBM
Russell Butek is an IBM SOA and Web services consultant. He has been one of the developers of the IBM WebSphere Web services engine. He has also been a member 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.

Summary:  This article details the Java™ API for XML Web Services (JAX-WS) mapping of Web Services Description Language (WSDL) faults to Java exceptions, Java exceptions to WSDL faults, and some other exceptions defined by the JAX-WS specification.

Date:  30 Oct 2008
Level:  Intermediate PDF:  A4 and Letter (34KB)Get Adobe® Reader®
Activity:  11818 views
Comments:  

Introduction

IBM® developerWorks has published articles about Java API for XML-based RPC (JAX-RPC) faults and exceptions (see Resources). But now there's a new Web services Java mapping specification: JAX-WS. JAX-WS mappings are somewhat different from JAX-RPC mappings. This article describes these new mappings. (Comparing the JAX-RPC and JAX-WS fault mappings is beyond the scope of this article. Feel free to do your own comparison by checking out other developerWorks JAX-RPC articles listed in Resources.)


WSDL-to-Java mapping

First, let's look at the WSDL-to-Java mapping of faults to exceptions, starting with the WSDL in Listing 1. Run your favorite JAX-WS WSDL-to-Java code generator on this WSDL. It gives you the generated interface and fault classes shown in Listings 2, 3, and 4. (It would generate much more, but you're only concerned with exceptions here.)


Listing 1. Faults.wsdl
<wsdl:definitions targetNamespace="urn:fault.sample"
    xmlns:tns="urn:fault.sample" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
  <wsdl:types>
    <xsd:schema targetNamespace="urn:fault.sample"
        xmlns:tns="urn:fault.sample" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <xsd:element name="op" type="tns:Op"/>
      <xsd:complexType name="Op">
        <xsd:sequence>
          <xsd:element name="in" type="xsd:string"/>
        </xsd:sequence>
      </xsd:complexType>
      <xsd:element name="opResponse" type="tns:OpResponse"/>
      <xsd:complexType name="OpResponse">
        <xsd:sequence>
          <xsd:element name="out" type="xsd:string"/>
        </xsd:sequence>
      </xsd:complexType>
      <xsd:element name="faultElement" type="tns:Fault"/>
      <xsd:complexType name="Fault">
        <xsd:sequence>
          <xsd:element name="code" type="xsd:string"/>
        </xsd:sequence>
      </xsd:complexType>
    </xsd:schema>
  </wsdl:types>
  <wsdl:message name="opRequest">
    <wsdl:part name="parameters" element="tns:op"/>
  </wsdl:message>
  <wsdl:message name="opResponse">
    <wsdl:part name="parameters" element="tns:opResponse"/>
  </wsdl:message>
  <wsdl:message name="faultMsg">
    <wsdl:part name="parameters" element="tns:faultElement"/>
  </wsdl:message>
  <wsdl:portType name="PT">
    <wsdl:operation name="op">
      <wsdl:input message="tns:opRequest"/>
      <wsdl:output message="tns:opResponse"/>
      <wsdl:fault name="fault" message="tns:faultMsg"/>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="Binding" type="tns:PT">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="op">
      <soap:operation soapAction=""/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
      <wsdl:fault name="fault">
        <soap:fault use="literal" name="fault"/>
      </wsdl:fault>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="Service">
    <wsdl:port name="Port" binding="tns:Binding">
      <soap:address location="http://www.example.org/"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

Notice in Listing 1 that I intentionally named each fault component differently so that you can see the source for the names of the Java classes.

  • The Java exception name is derived from the WSDL fault message's name; in this case FaultMsg.
  • All mapped JAX-WS exceptions contain a private faultInfo instance variable. The type of this faultInfo is derived from the schema, which the fault's wrapper element refers to; in this case it's Fault.

Note: Comments and annotations in the following listings have been removed from the generated Java code for brevity.


Listing 2. Generated Java interface: PT.java
package sample.fault;

public interface PT {
    public String op(String in) throws FaultMsg;
}


Listing 3. Generated Java exception: FautMsg.java
package sample.fault;

public class FaultMsg extends Exception {
    private Fault faultInfo;
    public FaultMsg(String message, Fault faultInfo) {...}
    public FaultMsg(String message, Fault faultInfo, Throwable cause) {...}
    public Fault getFaultInfo() {...}
}


Listing 4. Generated Java fault info class: Fault.java
package sample.fault;

public class Fault {
    protected String code;
    public String getCode() {...}
    public void setCode(String value) {...}
}

Why does a JAX-WS mapping of faults create a fault class and a fault info class? JAX-RPC didn't do that. The reason is that JAX-WS delegates the generation of schema mappings to Java Architecture for XML Binding (JAXB). JAX-WS knows how to do Web services stuff, but it doesn't know how to do schema stuff. JAXB knows schema. A fault or exception is a Web services artifact. The data in a fault is a schema artifact. So the JAX-WS generator generates the exception, and the JAXB generator generates the Java bean containing the exception's data.


Java-to-WSDL mapping

JAX-WS seems to prefer that you build exceptions like the ones it generates, with the exception itself separate from the Java bean data for the exception. If you follow this pattern, you get the reverse of the mapping described in the previous section.

But separating the exception data from the exception is not typical of how a Java programmer writes exceptions. So JAX-WS also provides a mapping for the more natural exception. A simple example of this natural pattern is shown in Listings 5 and 6. Listing 7 shows the WSDL that a JAX-WS generator can create from it.


Listing 5. Natural PT.java
package sample2.fault;

public interface PT {
  public String op(String in) throws Fault;
}


Listing 6. Natural Fault.java
package sample2.fault;

public class Fault extends Exception {
    public Fault(String code) {...}
    public String getCode() {...}
    public void setCode(String value) {...}
}

The JAX-WS mapping of exceptions to faults is essentially identical to the JAX-RPC mapping.


Listing 7. WSDL generated from above Java: PTImplService.wsdl
<definitions targetNamespace="http://fault.sample2/"
    xmlns:tns="http://fault.sample2/" xmlns="http://schemas.xmlsoap.org/wsdl/"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
  <types>
    <xsd:schema>
      <xsd:import
          namespace="http://fault.sample2/"
          schemaLocation="PTImplService_schema1.xsd"/>
    </xsd:schema>
  </types>
  <message name="op">
    <part element="tns:op" name="parameters"/>
  </message>
  <message name="opResponse">
    <part element="tns:opResponse" name="parameters"/>
  </message>
  <message name="Fault">
    <part element="tns:Fault" name="fault"/>
  </message>
  <portType name="PTImpl">
    <operation name="op">
      <input message="tns:op"/>
      <output message="tns:opResponse"/>
      <fault message="tns:Fault" name="Fault"/>
    </operation>
  </portType>
  <binding name="PTImplPortBinding" type="tns:PTImpl">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <operation name="op">
      <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
      <fault name="Fault">
        <soap:fault name="Fault" use="literal"/>
      </fault>
    </operation>
  </binding>
  <service name="PTImplService">
    <port binding="tns:PTImplPortBinding" name="PTImplPort">
      <soap:address location="https://localhost:9444/SampleFault/PTImplService"/>
    </port>
  </service>
</definitions>


Listing 8. Schema generated from above Java: PTImplService_schema1.xsd
<xs:schema targetNamespace="http://fault.sample2/"
        xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://fault.sample2/">

  <xs:element name="Fault" type="tns:Fault"/>

  <xs:element name="op" type="tns:op"/>

  <xs:element name="opResponse" type="tns:opResponse"/>

  <xs:complexType name="op">
    <xs:sequence>
      <xs:element minOccurs="0" name="arg0" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="opResponse">
    <xs:sequence>
      <xs:element minOccurs="0" name="return" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="Fault">
    <xs:sequence>
      <xs:element minOccurs="0" name="code" type="xs:string"/>
      <xs:element minOccurs="0" name="message" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>
</xs:schema>


What about unmodeled faults?

What happens when an unmodeled fault occurs? For example, what happens when the service above throws an exception other than sample2.fault.Fault (for instance, NullPointerException)? What happens on the client? The answer to that depends on the messaging protocol. For instance, when communicating via SOAP/HTTP, the server-side SOAP engine creates a SOAP message containing a SOAP fault (see Listing 9) with information relevant to the problem in the faultcode and faultstring fields. Because a SOAP fault is returned to the client, JAX-WS has defined an exception named SOAPFaultException. When the service throws an unmodeled fault, the client receives a SOAPFaultException.

javax.xml.ws.soap.SOAPFaultException is a protocol-specific exception. It extends javax.xml.ws.ProtocolException. JAX-WS defines another extension of ProtocolException: javax.xml.ws.http.HTTPException for the XML/HTTP communication channel. Those are the only standardized bindings defined for WSDL. For other bindings, assume the binding provider defines other extensions of ProtocolException, one for each new binding.


Listing 9. SOAP fault response message
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Body>
    <soapenv:Fault>
      <faultcode>soapenv:Server</faultcode>
      <faultstring>java.lang.NullPointerException</faultstring>
      <detail/>
    </soapenv:Fault>
  </soapenv:Body>
</soapenv:Envelope>


Other exceptions

There are two other exceptions to note: WebServiceException and ExecutionException.

WebServiceException

javax.xml.ws.WebServiceException is not particularly interesting. JAX-WS defines a number of Java classes, such as Service, BindingProvider, and Dispatch. If calls to those classes fail, they throw WebServiceException, the general-purpose exception for the JAX-WS APIs.

ExecutionException

java.util.concurrent.ExecutionException is not a JAX-WS exception (as you can tell from the package name); it's part of the Java Futures model. Because JAX-WS's asynchronous client programming models rely on the Java Future's model, it makes use of this exception. In the Futures model, exceptions thrown by asynchronous calls aren't thrown directly. They are wrapped by an ExecutionException. This exception is thrown when the client tries to get the response from an asynchronous call. Listing 10 shows a code snippet that makes an asynchronous call to the Web service defined in Listing 1. It makes the call (to proxy.opAsync), then does something until the asynchronous call is done. When it's done it gets the response. If the service throws an exception, then this code falls into the catch block. The actual exception that the service throws is in the cause field of the ExecutionException instance. (For more details on the asynchronous client programming model, see Resources.)


Listing 10. Asynchronous exception snippet
  try {
    PortProxy proxy = new PortProxy();
    Response<OpResponse> response = proxy.opAsync("NPE");
    while (!response.isDone()) {
      // do something
    }
    OpResponse opR = response.get(); // This call fails if there is a fault
    System.out.println("response = " + opR.getOut());
  } catch (ExecutionException ee) {
    ee.printStackTrace();
    Throwable t = ee.getCause();
    System.out.println("t = " + t.getClass().getName());
  }


Summary

This article showed you an example of a JAX-WS mapping of a WSDL fault to a Java exception. You also saw a mapping from a Java exception to a WSDL fault. Then you explored other JAX-WS exceptions:

  • SOAPFaultException and its relatives, used when the client receives an unmodeled fault
  • WebServiceException, used in the JAX-WS APIs
  • ExecutionException, used in asynchronous client programs

Resources

Learn

Get products and technologies

  • Download IBM product evaluation versions and get your hands on application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.

Discuss

About the author

Russell Butek is an IBM SOA and Web services consultant. He has been one of the developers of the IBM WebSphere Web services engine. He has also been a member 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.

Comments



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
ArticleID=348637
ArticleTitle=Faults and exceptions in JAX-WS
publish-date=10302008
author1-email=butek@us.ibm.com
author1-email-cc=flanders@us.ibm.com

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