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.)
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
faultInfoinstance variable. The type of thisfaultInfois derived from the schema, which the fault's wrapper element refers to; in this case it'sFault.
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.
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 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> |
There are two other exceptions to note: WebServiceException and
ExecutionException.
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.
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());
} |
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:
SOAPFaultExceptionand its relatives, used when the client receives an unmodeled faultWebServiceException, used in the JAX-WS APIsExecutionException, used in asynchronous client programs
Learn
- Get the specification, API classes, and
Javadocs for
JAX-RPC 1.1.
- Get the specification, API classes, and
Javadocs for
JAX-WS 2.0.
- Get the specification, API classes, and
Javadocs for
JAXB 2.0.
- Learn about all the features of
Java 5.
- Read the
WSDL 1.1 specification.
- Evaluate JAX-WS features with the
IBM WebSphere Application Server Version 6.1 Feature Pack for Web Services.
- Read
"JAX-RPC versus JAX-WS, Part 3, the service endpoint interface"
(developerWorks, Jun 2007) for a high-level comparison of
the interface mappings between the two specifications.
- Check out
"Exception handling with JAX-RPC"
(developerWorks, Feb 2004), which is roughly equivalent to this article for
JAX-RPC.
- Read
"JAX-WS
client APIs in the Web Services Feature Pack for WAS V6.1: Using the JAX-WS asyn programming model"
(developerWorks, Apr 2008).
- The SOA and web services zone on IBM developerWorks hosts hundreds of informative articles and introductory, intermediate, and advanced tutorials on how to develop web services
applications.
- Play in the IBM SOA Sandbox! Increase your SOA skills through practical, hands-on experience with the IBM SOA entry points.
- The IBM SOA web site offers an overview of SOA and how IBM can help you get there.
- Stay current with developerWorks technical events and webcasts.
- Browse for books on these and other technical topics at the
Safari bookstore.
- Check out a quick web services on demand demo.
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
- Participate in the discussion forum.
- Get involved in the developerWorks community
by participating in developerWorks blogs.
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.




