19 Handling Exceptions Using SOAP Faults
This chapter includes the following sections:
Overview of Exception Handling Using SOAP Faults
When a web service request is being processed, if an error is encountered, the nature of the error needs to be communicated to the client, or sender of the request. Because clients can be written on a variety of platforms using different languages, there must exist a standard, platform-independent mechanism for communicating the error.
The SOAP specification (available at http://www.w3.org/TR/soap/
) defines a standard, platform-independent way of describing the error within the SOAP message using a SOAP fault. In general, a SOAP fault is analogous to an application exception. SOAP faults are generated by receivers to report business logic errors or unexpected conditions.
In JAX-WS, Java exceptions (java.lang.Exception
) that are thrown by your Java web service are mapped to a SOAP fault and returned to the client to communicate the reason for failure. SOAP faults can be one of the following types:
-
Modeled—Maps to an exception that is thrown explicitly from the business logic of the Java code and mapped to
wsdl:fault
definitions in the WSDL file, when the web service is deployed. In this case, the SOAP faults are predefined. -
Unmodeled—Maps to an exception (for example,
java.lang.RuntimeException
) that is generated at run-time when no business logic fault is defined in the WSDL. In this case, Java exceptions are represented as generic SOAP fault exceptions,javax.xml.ws.soap.SOAPFaultException
.
The faults are returned to the sender only if request/response messaging is in use. If a web service operation is configured as one-way, the SOAP fault is not returned to the sender, but stored for further processing.
As illustrated in Figure 19-1, JAX-WS handles SOAP fault processing during SOAP protocol binding. The SOAP binding maps exceptions to SOAP fault messages.
Contents of the SOAP Fault Element
The SOAP <Fault>
element is used to transmit error and status information within a SOAP message. The <Fault>
element is a child of the body element. There can be only one <Fault>
element in the body of a SOAP message.
The SOAP <Fault>
element contents for SOAP 1.2 and 1.1 are defined in the following sections:
SOAP 1.2 <Fault> Element Contents
The <Fault>
element for SOAP 1.2 contains the subelements defined in Table 19-1.
Table 19-1 Subelements of the SOAP 1.2 <Fault> Element
Subelement | Description | Required? |
---|---|---|
|
Information pertaining to the fault error code. The
The subelements are defined below. |
Required |
|
Code value that provides more information about the fault. A set of code values is predefined by the SOAP specification, including:
|
Required |
|
Subcode value that provides more information about the fault. This subelement can have a recursive structure. |
Optional |
|
Human-readable description of fault. The |
Required |
|
Information regarding the actor (SOAP node) that caused the fault. |
Optional |
|
Role being performed by actor at the time of the fault. |
Optional |
|
Application-specific information, such as the exception that was thrown. |
Optional |
The following provides an example of a SOAP 1.2 fault message.
Example 19-1 Example of SOAP 1.2 Fault Message
<?xml version="1.0"?> <env:Envelope xmlns:env=http://www.w3.org/2003/05/soap-envelope> <env:Body> <env:Fault> <env:Code> <env:Value>env:Sender</env:Value> <env:Subcode> <env:Value>rpc:BadArguments</env:Value> </env:Subcode> </env:Code> <env:Reason> <env:Text xml:lang=en-US>Processing error<env:Text> </env:Reason> <env:Detail> <e:myFaultDetails xmlns:e=http://travelcompany.example.org/faults> <e:message>Name does not match card number</e:message> <e:errorcode>999</e:errorcode> </e:myFaultDetails> </env:Detail> </env:Fault> </env:Body> </env:Envelope>
SOAP 1.1 <Fault> Element Contents
The <Fault>
element for SOAP 1.1 contains the subelements defined in Table 19-2.
Table 19-2 Subelements of the SOAP 1.1 <Fault> Element
Subelement | Description |
---|---|
|
Standard code that provides more information about the fault. A set of code values is predefined by the SOAP specification, as defined below. This set of fault code values can be extended by the application. Predefined fault code values include:
|
|
Human-readable description of fault. |
|
URI associated with the actor (SOAP node) that caused the fault. In RPC-style messaging, the actor is the URI of the web service. |
|
Application-specific information, such as the exception that was thrown. This element can be an XML structure or plain text. |
The following provides an example of a SOAP 1.1 fault message.
Example 19-2 Example of SOAP 1.1 Fault Message
<?xml version="1.0"?> <soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope'> <soap:Body> <soap:Fault> <faultcode>soap:VersionMismatch</faultcode> <faultstring, xml:lang='en"> Message was not SOAP 1.1 compliant </faultstring> <faultactor> http://sample.org.ocm/jws/authnticator </faultactor> </soap:Fault> </soap:Body> </soap:Envelope>
Using Modeled Faults
As described previously, a modeled fault is mapped to an exception that is thrown explicitly from the business logic of the Java code. In this case, the exception is mapped to a wsdl:fault
definitions in the WSDL file, when the web service is deployed.
The following sections provide more information about using modeled faults:
Creating and Using a Custom Exception
To use modeled faults, you need to create a custom Java exception and throw it from within your web service.
Example 19-3 provides a simple example of a custom exception being thrown by a web service. The exception is called MissingName
and is thrown when the input argument is empty.
Example 19-3 Web Service With Custom Exception
package examples; import javax.jws.WebService; @WebService(name="HelloWorld", serviceName="HelloWorldService") public class HelloWorld { public String sayHelloWorld(String message) throws MissingName { System.out.println("Say Hello World: " + message); if (message == null || message.isEmpty()) { throw new MissingName(); } return "Here is the message: '" + message + "'"; } }
Example 19-4 shows the he class for the exception, MissingName.java
.
Example 19-4 Custom Exception Class (MissingName)
package examples; import java.lang.Exception; public class MissingName extends Exception { public MissingName() { super("Your name is required."); } }
How Modeled Faults are Mapped in the WSDL File
The JAX-WS Java-to-WSDL mapping binds subclasses of java.lang.Exception
to wsdl:fault
messages. Example 19-4 shows the WSDL that is generated from the annotated web service in Example 19-3.
In this example:
-
The
<message name="MissingName">
element defines the parts of theMissingName
message, namelyfault
, and its associated data type,tns:MissingName
.<message name="MissingName"> <part name="fault" element="tns:MissingName" /> </message>
-
The
MissingName
SOAP fault is mapped to thesayHelloWorld
operation.<operation name="sayHelloWorld"> <input message="tns:sayHelloWorld" /> <output message="tns:sayHelloWorldResponse" /> <fault message="tns:MissingName" name="MissingName" /> </operation>
This
<fault>
subelement in this example is derived from thethrows MissingName
clause of thesayHelloWorld()
method declaration (see Example 19-3).public String sayHelloWorld(String message) throws MissingName { ... }
-
The fault message is mapped to the
sayHelloWorld
operation in the<binding>
element, as well.<fault name="MissingName"> <soap:fault name="MissingName" use="literal" /> </fault>
Example 19-5 Example of WSDL with Modeled Exceptions
<?xml version="1.0" encoding="UTF-8" ?> <definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://examples/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://examples/" name="HelloWorldService"> <types> <xsd:schema> <xsd:import namespace="http://examples/" schemaLocation="http://localhost:7001/HelloWorld/HelloWorldService?xsd=1"/> </xsd:schema> </types> <message name="sayHelloWorld"> <part name="parameters" element="tns:sayHelloWorld" /> </message> <message name="sayHelloWorldResponse"> <part name="parameters" element="tns:sayHelloWorldResponse" /> </message> <message name="MissingName"> <part name="fault" element="tns:MissingName" /> </message> <portType name="HelloWorld"> <operation name="sayHelloWorld"> <input message="tns:sayHelloWorld" /> <output message="tns:sayHelloWorldResponse" /> <fault message="tns:MissingName" name="MissingName" /> </operation> </portType> <binding name="HelloWorldPortBinding" type="tns:HelloWorld"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" /> <operation name="sayHelloWorld"> <soap:operation soapAction="" /> <input> <soap:body use="literal" /> </input> <output> <soap:body use="literal" /> </output> <fault name="MissingName"> <soap:fault name="MissingName" use="literal" /> </fault> </operation> </binding> <service name="HelloWorldService"> <port name="HelloWorldPort" binding="tns:HelloWorldPortBinding"> <soap:address location="http://localhost:7001/HelloWorld/HelloWorldService" /> </port> </service>
How the Fault is Communicated in the SOAP Message
Example 19-6 shows how the SOAP fault is communicated in the resulting SOAP message when the MissingName
Java exception is thrown.
Example 19-6 Example SOAP Fault Message for MissingName Exception
<?xml version = '1.0' encoding = 'UTF-8'?> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Body> <S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope"> <faultcode>S:Server</faultcode> <faultstring>Your name is required.</faultstring> <detail> <ns2:MissingName xmlns:ns2="http://examples/"> <message>Your name is required.</message> </ns2:MissingName> <ns2:exception xmlns:ns2="http://jax-ws.java.net/" class="examples.MissingName" note="To disable this feature, set com.sun.xml.ws.fault.SOAPFaultBuilder.disableCaptureStackTrace system property to false"> <message>Your name is required.</message> <ns2:stackTrace> <ns2:frame class="examples.HelloWorld" file="HelloWorld.java" line="14" method="sayHelloWorld"/> ... </ns2:stackTrace> </ns2:exception> </detail> </S:Fault> </S:Body> </S:Envelope>
Creating the Web Service Client
When you generate a web service client from a WSDL file that contains mapped faults using clientgen
, the required exception classes are generated automatically, including the mapped exception, fault bean, service implementation classes client implementation class, which you must modify, as described in the following sections.
For more information about clientgen, see clientgen in WebLogic Web Services Reference for Oracle WebLogic Server.
Reviewing the Generated Java Exception Class
An example of the generated Java exception class is shown in Example 19-7. The @WebFault
annotation identifies the class as a mapped exception.
Example 19-7 Example of Generated Java Exception Class
package examples.client; import javax.xml.ws.WebFault; @WebFault(name = "MissingName", targetNamespace = "http://examples/") public class MissingName_Exception extends Exception { private MissingName faultInfo; public MissingName_Exception(String message, MissingName faultInfo) { ... } public MissingName_Exception(String message, MissingName faultInfo, Throwable cause) { ... } public MissingName getFaultInfo() { ... } }
Reviewing the Generated Java Fault Bean Class
An example of the generated Java fault bean class is shown in Example 19-8, defining the getters and setters for the fault message.
Example 19-8 Example of Generated Java Fault Bean Class
package examples.client; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlType; @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "MissingName", propOrder = { "message" }) public class MissingName { protected String message; public String getMessage() { return message; } public void setMessage(String value) { this.message = value; } }
Reviewing the Client-side Service Implementation
An example of the generated client-side service implementation class is shown in Example 19-9.
Example 19-9 Client-side Service Implementation
package examples.client; ... @WebService(name = "HelloWorld", targetNamespace = "http://examples/") @XmlSeeAlso({ ObjectFactory.class }) public interface HelloWorld { @WebMethod @WebResult(targetNamespace = "") @RequestWrapper(localName = "sayHelloWorld", targetNamespace = "http://examples/", className = "examples.client.SayHelloWorld") @ResponseWrapper(localName = "sayHelloWorldResponse", targetNamespace = "http://examples/", className = "examples.client.SayHelloWorldResponse") public String sayHelloWorld( @WebParam(name = "arg0", targetNamespace = "") String arg0) throws MissingName_Exception; }
Creating the Client Implementation Class
Create the client implementation class to call the web service method and throw the custom exception. Then, compile and run the client. For more information about creating web service clients, see Invoking Web Services in Developing JAX-WS Web Services for Oracle WebLogic Server.
Example 19-10 shows an example client implementation class.
Example 19-10 Client Implementation Class
package examples.client; import javax.xml.namespace.QName; import java.net.MalformedURLException; import java.net.URL; import examples.client.MissingName_Exception; public class Main { public static void main(String[] args) throws MissingName_Exception { HelloWorldService service; try { service = new HelloWorldService(new URL(args[0] + "?WSDL"), new QName("http://examples/", "HelloWorldService") ); } catch (MalformedURLException murl) { throw new RuntimeException(murl); } HelloWorld port = service.getHelloWorldPort(); String result = null; try { result = port.sayHelloWorld(""); } catch (MissingName_Exception e) { System.err.println("Error: " + e); } System.out.println( "Got result: " + result ); } }
Using Unmodeled Faults
As noted previously, an unmodeled fault maps to an exception (for example, java.lang.RuntimeException
) that is generated at run-time when no business logic fault is defined in the WSDL. In this case, Java exceptions are represented as generic SOAP fault exceptions, javax.xml.ws.soap.SOAPFaultException
.
The following shows an example of an exception that maps to an unmodeled fault.
Example 19-11 Example of Web Service Using Unmodeled Fault
package examples;
import javax.jws.WebService;
@WebService(name="HelloWorld", serviceName="HelloWorldService")
public class HelloWorld {
public String sayHelloWorld(String message) throws MissingName {
System.out.println("Say Hello World: " + message);
if (message == null || message.isEmpty()) {
throw new MissingName(); // Modeled fault
} else if (message.equalsIgnoreCase("abc")) {
throw new RuntimeException("Please enter a name."); //Unmodeled fault
}
return "Here is the message: '" + message + "'";
}
}
In this example, if the string "abc" is passed to the method, the following SOAPFaultException
and RuntimeException
messages are returned in the log file:
Example 19-12 Example of Log File Message for Unmodeled Fault
... run: [java] Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: Please enter a name. ... Caused by: java.lang.RuntimeException: Please enter a name.\ ...
Customizing the Exception Handling Process
You can customize the SOAP fault handling process using SOAP message handlers. A SOAP message handler provides a mechanism for intercepting the SOAP message in both the request and response of the web service. You can create SOAP message handlers to enable web services and clients to perform additional processing on the SOAP message. For more information, see Creating and Using SOAP Message Handlers.
Disabling the Stack Trace from the SOAP Fault
Note:
The com.sun.xml.ws.fault.SOAPFaultBuilder.disableCaptureStackTrace
property is supported as an extension to the JDK 6.0. Because this API is not provided as part of the JDK 6.0 kit, it is subject to change.
By default, the entire stack trace, including nested exceptions, is included in the details of the SOAP fault message. For example, the following shows an example of a SOAP fault message that includes the stack trace:
You can disable the inclusion of the stack trace in the SOAP fault message by setting the com.sun.xml.ws.fault.SOAPFaultBuilder.disableCaptureStackTrace
Java startup property to false
.
To disable the stack trace:
Example 19-13 Example of Stack Trace in SOAP Fault Message
<?xml version = '1.0' encoding = 'UTF-8'?> <S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope"> <S:Body> <S:Fault xmlns:ns4="http://schemas.xmlsoap.org/soap/envelope/"> <S:Code> <S:Value>S:Receiver</S:Value> </S:Code> <S:Reason> <S:Text xml:lang="en">String index out of range: 3</S:Text> </S:Reason> <S:Detail> <ns2:exception xmlns:ns2="http://jax-ws.java.net/" class="java.lang.StringIndexOutOfBoundsException" note="To disable this feature, set com.sun.xml.ws.fault.SOAPFaultBuilder.disableCaptureStackTrace system property to false"> <message>String index out of range: 3</message> <ns2:stackTrace> <ns2:frame class="java.lang.String" file="String.java" line="1934" method="substring"/> <ns2:frame class="ratingservice.CreditRating" file="CreditRating.java" line="21" method="processRating"/> <ns2:frame class="sun.reflect.NativeMethodAccessorImpl" file="NativeMethodAccessorImpl.java" line="native" method="invoke0"/> <ns2:frame class="sun.reflect.NativeMethodAccessorImpl" file="NativeMethodAccessorImpl.java" line="39" method="invoke"/> <ns2:frame class="sun.reflect.DelegatingMethodAccessorImpl" file="DelegatingMethodAccessorImpl.java" line="25" method="invoke"/> <ns2:frame class="java.lang.reflect.Method" file="Method.java" line="597" method="invoke"/> ... </ns2:stackTrace> </ns2:exception> </S:Detail> </S:Fault> </S:Body> </S:Envelope>
Other Exceptions
Note that in addition to the custom exceptions that are thrown explicitly in your web service and the SOAPFaultExceptions
that are used to map exceptions that are not caught by your business logic, there are two other exceptions that might be communicated to the web service client, and that you should be aware of.
Table 19-3 Other Exceptions
Exception | Description |
---|---|
|
Base exception for all JAX-WS API runtime exceptions, used when calls to JAX-WS Java classes fail, such as |
|
Used by JAX-WS asynchronous calls, when a client tries to get the response from an asynchronous call. |