Working with custom Exceptions
Custom exceptions in JAXRPC are about definig SOAP faults in your abstract contract and
mapping
them to java exceptions. The SOAP message contains a <soap:fault> element that contains information about
the cause of the fault. Java specifics like stack traces, exception class names,
etc. are usually
not transported because they maybe meaningless to the non-java receiver.
A good article about Exception Handling with JAX-RPC can be found at IBM's developerworks.
Lets use a service endpoint interface (SEI) that throws various user exception
public interface ExceptionServiceInterface extends Remote { void throwException() throws UserException, RemoteException; void throwExceptionWithMessage(String message) throws UserMessageException, RemoteException; void throwComplexUserException(String message, int code) throws ComplexUserException, RemoteException; void throwComplexUserArrayException(String message, int[] code) throws ComplexUserArrayException, RemoteException;
wscompile produces the following abstract contract (WSDL) when invoked like this:
<!-- wscompile -cp ../../../../output/classes -gen:server -f:rpcliteral -mapping jaxrpc-mapping.xml config.xml --> <configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config"> <service name="ExceptionService" targetNamespace="http://org.jboss.webservice/exception" typeNamespace="http://org.jboss.webservice/exception/types" packageName="org.jboss.test.webservice.exception"> <interface name="org.jboss.test.webservice.exception.ExceptionServiceInterface"></interface> </service> </configuration> <?xml version="1.0" encoding="UTF-8"?> <definitions name="ExceptionService" targetNamespace="http://org.jboss.webservice/exception" xmlns:tns="http://org.jboss.webservice/exception" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:ns2="http://org.jboss.webservice/exception/types/arrays/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:ns3="http://org.jboss.webservice/exception/types"> <types> <schema targetNamespace="http://org.jboss.webservice/exception/types/arrays/" xmlns:tns="http://org.jboss.webservice/exception/types/arrays/" xmlns:soap11-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://www.w3.org/2001/XMLSchema"> <import namespace="http://org.jboss.webservice/exception/types"></import> <complexType name="intArray"> <sequence> <element name="value" type="int" minOccurs="0" maxOccurs="unbounded"></element> </sequence> </complexType> </schema> <schema targetNamespace="http://org.jboss.webservice/exception/types" xmlns:tns="http://org.jboss.webservice/exception/types" xmlns:soap11-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://www.w3.org/2001/XMLSchema"> <import namespace="http://org.jboss.webservice/exception/types/arrays/"></import> <complexType name="ComplexUserArrayException"> <sequence> <element name="message" type="string" nillable="true"></element> <element name="errorCodes" type="int" minOccurs="0" maxOccurs="unbounded"></element> </sequence> </complexType> <complexType name="ComplexUserException"> <sequence> <element name="message" type="string" nillable="true"></element> <element name="errorCode" type="int"></element> </sequence> </complexType> <complexType name="UserException"> <sequence></sequence> </complexType> <complexType name="UserMessageException"> <sequence> <element name="message" type="string" nillable="true"></element> </sequence> </complexType> <element name="ComplexUserArrayException" type="tns:ComplexUserArrayException"></element> <element name="ComplexUserException" type="tns:ComplexUserException"></element> <element name="UserException" type="tns:UserException"></element> <element name="UserMessageException" type="tns:UserMessageException"></element> </schema> </types> <message name="ExceptionServiceInterface_throwComplexUserArrayException"> <part name="String_1" type="xsd:string"></part> <part name="arrayOfint_2" type="ns2:intArray"></part> </message> <message name="ExceptionServiceInterface_throwComplexUserArrayExceptionResponse"></message> <message name="ComplexUserArrayException"> <part name="ComplexUserArrayException" element="ns3:ComplexUserArrayException"></part> </message> <message name="ExceptionServiceInterface_throwComplexUserException"> <part name="String_1" type="xsd:string"></part> <part name="int_2" type="xsd:int"></part> </message> <message name="ExceptionServiceInterface_throwComplexUserExceptionResponse"></message> <message name="ComplexUserException"> <part name="ComplexUserException" element="ns3:ComplexUserException"></part> </message> <message name="ExceptionServiceInterface_throwException"></message> <message name="ExceptionServiceInterface_throwExceptionResponse"></message> <message name="UserException"> <part name="UserException" element="ns3:UserException"></part> </message> <message name="ExceptionServiceInterface_throwExceptionWithMessage"> <part name="String_1" type="xsd:string"></part> </message> <message name="ExceptionServiceInterface_throwExceptionWithMessageResponse"></message> <message name="UserMessageException"> <part name="UserMessageException" element="ns3:UserMessageException"></part> </message> <portType name="ExceptionServiceInterface"> <operation name="throwComplexUserArrayException" parameterOrder="String_1 arrayOfint_2"> <input message="tns:ExceptionServiceInterface_throwComplexUserArrayException"/> <output message="tns:ExceptionServiceInterface_throwComplexUserArrayExceptionResponse"></output> <fault name="ComplexUserArrayException" message="tns:ComplexUserArrayException"></fault> </operation> <operation name="throwComplexUserException" parameterOrder="String_1 int_2"> <input message="tns:ExceptionServiceInterface_throwComplexUserException"/> <output message="tns:ExceptionServiceInterface_throwComplexUserExceptionResponse"></output> <fault name="ComplexUserException" message="tns:ComplexUserException"></fault> </operation> <operation name="throwException"> <input message="tns:ExceptionServiceInterface_throwException"/> <output message="tns:ExceptionServiceInterface_throwExceptionResponse"></output> <fault name="UserException" message="tns:UserException"></fault> </operation> <operation name="throwExceptionWithMessage" parameterOrder="String_1"> <input message="tns:ExceptionServiceInterface_throwExceptionWithMessage"/> <output message="tns:ExceptionServiceInterface_throwExceptionWithMessageResponse"></output> <fault name="UserMessageException" message="tns:UserMessageException"></fault> </operation> </portType> <binding name="ExceptionServiceInterfaceBinding" type="tns:ExceptionServiceInterface"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"></soap:binding> <operation name="throwComplexUserArrayException"> <soap:operation soapAction=""></soap:operation> <input> <soap:body use="literal" namespace="http://org.jboss.webservice/exception"></soap:body> </input> <output> <soap:body use="literal" namespace="http://org.jboss.webservice/exception"></soap:body> </output> <fault name="ComplexUserArrayException"> <soap:fault name="ComplexUserArrayException" use="literal"></soap:fault> </fault> </operation> <operation name="throwComplexUserException"> <soap:operation soapAction=""></soap:operation> <input> <soap:body use="literal" namespace="http://org.jboss.webservice/exception"></soap:body> </input> <output> <soap:body use="literal" namespace="http://org.jboss.webservice/exception"></soap:body> </output> <fault name="ComplexUserException"> <soap:fault name="ComplexUserException" use="literal"></soap:fault> </fault> </operation> <operation name="throwException"> <soap:operation soapAction=""></soap:operation> <input> <soap:body use="literal" namespace="http://org.jboss.webservice/exception"></soap:body> </input> <output> <soap:body use="literal" namespace="http://org.jboss.webservice/exception"></soap:body> </output> <fault name="UserException"> <soap:fault name="UserException" use="literal"></soap:fault> </fault> </operation> <operation name="throwExceptionWithMessage"> <soap:operation soapAction=""></soap:operation> <input> <soap:body use="literal" namespace="http://org.jboss.webservice/exception"></soap:body> </input> <output> <soap:body use="literal" namespace="http://org.jboss.webservice/exception"></soap:body> </output> <fault name="UserMessageException"> <soap:fault name="UserMessageException" use="literal"></soap:fault> </fault> </operation> </binding> <service name="ExceptionService"> <port name="ExceptionServiceInterfacePort" binding="tns:ExceptionServiceInterfaceBinding"> <soap:address location="REPLACE_WITH_ACTUAL_URL"></soap:address> </port> </service> </definitions>
Notice the various fault elements and how they are linked to XML schema complex types. The WSDL does not contain any information about the java mapping. This is defined in jaxrpc-maping.xml, for which I will only show the exception relevant parts.
<exception-mapping> <exception-type>org.jboss.test.webservice.exception.UserMessageException</exception-type> <wsdl-message xmlns:exMsgNS="http://org.jboss.webservice/exception">exMsgNS:UserMessageException</wsdl-message> <constructor-parameter-order> <element-name>message</element-name> </constructor-parameter-order> </exception-mapping> <exception-mapping> <exception-type>org.jboss.test.webservice.exception.ComplexUserException</exception-type> <wsdl-message xmlns:exMsgNS="http://org.jboss.webservice/exception">exMsgNS:ComplexUserException</wsdl-message> <constructor-parameter-order> <element-name>message</element-name> <element-name>errorCode</element-name> </constructor-parameter-order> </exception-mapping> <exception-mapping> <exception-type>org.jboss.test.webservice.exception.UserException</exception-type> <wsdl-message xmlns:exMsgNS="http://org.jboss.webservice/exception">exMsgNS:UserException</wsdl-message> </exception-mapping> <exception-mapping> <exception-type>org.jboss.test.webservice.exception.ComplexUserArrayException</exception-type> <wsdl-message xmlns:exMsgNS="http://org.jboss.webservice/exception">exMsgNS:ComplexUserArrayException</wsdl-message> <constructor-parameter-order> <element-name>message</element-name> <element-name>errorCodes</element-name> </constructor-parameter-order> </exception-mapping>
Finaly, I'll show you some SOAP messages as they would appear on the wire
<soapenv:Envelope ...> <soapenv:Body> <soapenv:Fault> <faultcode>soapenv:Client</faultcode> <faultstring>org.jboss.test.webservice.exception.UserException</faultstring> <detail> <ns1:UserException xmlns:ns1="http://org.jboss.webservice/exception/types"> <message xsi:nil="1"></message> </ns1:UserException> </detail> </soapenv:Fault> </soapenv:Body> </soapenv:Envelope> <soapenv:Envelope ...> <soapenv:Body> <soapenv:Fault> <faultcode>soapenv:Client</faultcode> <faultstring>Don't worry it's just a test</faultstring> <detail> <ns1:UserMessageException xmlns:ns1="http://org.jboss.webservice/exception/types"> <message>Don't worry it's just a test</message> </ns1:UserMessageException> </detail> </soapenv:Fault> </soapenv:Body> </soapenv:Envelope> <soapenv:Envelope ...> <soapenv:Body> <soapenv:Fault> <faultcode>soapenv:Client</faultcode> <faultstring>Don't worry it's just a test</faultstring> <detail> <ns1:ComplexUserException xmlns:ns1="http://org.jboss.webservice/exception/types"> <message>Don't worry it's just a test</message> <errorCode>200</errorCode> </ns1:ComplexUserException> </detail> </soapenv:Fault> </soapenv:Body> </soapenv:Envelope> <soapenv:Envelope ...> <soapenv:Body> <soapenv:Fault> <faultcode>soapenv:Client</faultcode> <faultstring>Don't worry it's just a test</faultstring> <detail> <ns1:ComplexUserArrayException xmlns:ns1="http://org.jboss.webservice/exception/types"> <message>Don't worry it's just a test</message> <errorCodes>100</errorCodes> <errorCodes>200</errorCodes> </ns1:ComplexUserArrayException> </detail> </soapenv:Fault> </soapenv:Body> </soapenv:Envelope>
The example code is taken from the jboss testsuite. You can run the test like this:
cd jboss-4.0/testsuite ant -Dtest=org.jboss.test.webservice.exception.ExceptionTestCase one-test
Comments