In our last post we were able to deploy a simple JAX-WS service on both TomEE and WebSphere Application Server.
JAX-WS Specification suggests that three thing should be followed for us to implement Custom Exception as SOAP Fault.
WrapperException(String message, FaultBean faultInfo)
A constructor where WrapperException
is replaced with the name of the generated wrapper exception and FaultBean is replaced by the
name of the generated fault bean.
WrapperException(String message, FaultBean faultInfo, Throwable cause)
A constructor
whereWrapperException is replaced with the name of the generated wrapper exception and FaultBean
is replaced by the name of the generated fault bean. The last argument, cause, may be used to convey
protocol specific fault information, see section 6.4.1.
FaultBean getFaultInfo()
Getter to obtain the fault information, where FaultBean is replaced by the
name of the generated fault bean.
But as it turns out to be this is not very restrictive and not honored across Application Server. Let’s take the IMyService.java
and MyServiceImpl.java
from previous post and then we will modify the exception part.
Our updated Exception class will have a faultBean which will accept errorCode and errorMessage.
First the exception class MyException.java
, in below code we have introduced a new class MyExceptionBean
which holds our errorCode
and errorMessage
. We initialize this class with values which are passed to the constructor of our MyException
.
package com.test.mumz.soap.soapexp; import javax.xml.ws.WebFault; /** * The Class MyException. * * @author prabhat.jha */ @WebFault(name = "MyException") public class MyException extends Exception { /** The Constant serialVersionUID. */ private static final long serialVersionUID = -861826770198517502L; /** The my exception bean. */ private MyExceptionBean faultBean = null; /** * Instantiates a new my exception. * * @param errorCode * the error code * @param message * the message */ public MyException(String errorCode, String message) { prepareFaultBean(errorCode, message); } /** * Instantiates a new my exception. * * @param errorCode * the error code * @param message * the message * @param cause * the cause */ public MyException(String errorCode, String message, Throwable cause) { super(message, cause); prepareFaultBean(errorCode, message); } /** * Adds the exception details. * * @param errorCode the error code * @param errorMessage the error message * @return the my exception */ private void prepareFaultBean(String errorCode, String errorMessage) { this.faultBean = new MyExceptionBean(errorCode, errorMessage); } /** * Gets the fault bean. * * @return the fault bean */ public MyExceptionBean getFaultBean() { return faultBean; } }
Next is our MyExceptionBean.java
which is POJO and holds errorCode
and errorMessage
.
package com.test.mumz.soap.soapexp; /** * The Class MyExceptionBean. * * @author prabhat.jha */ public class MyExceptionBean { /** The error code. */ private String errorCode = null; /** The error message. */ private String errorMessage = null; /** * Instantiates a new my exception bean. * * @param errorCode * the error code * @param errorMessage * the error message */ public MyExceptionBean(String errorCode, String errorMessage) { this.errorCode = errorCode; this.errorMessage = errorMessage; } /** * @return the errorCode */ public String getErrorCode() { return errorCode; } /** * @param errorCode * the errorCode to set */ public void setErrorCode(String errorCode) { this.errorCode = errorCode; } /** * @return the errorMessage */ public String getErrorMessage() { return errorMessage; } /** * @param errorMessage * the errorMessage to set */ public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; } }
Next deploy it in TomEE and use SoapUI to test. Sample Input and Output are given below
Input
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:mpr="http://mprabhat.com/"> <soapenv:Header/> <soapenv:Body> <mpr:sayHello> <arg0></arg0> </mpr:sayHello> </soapenv:Body> </soapenv:Envelope>
Output
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <soap:Fault> <faultcode>soap:Server</faultcode> <faultstring>Fault occurred while processing.</faultstring> <detail> <ns1:MyException xmlns:ns1="http://mprabhat.com/"> <faultBean xsi:type="ns2:myExceptionBean" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns2="http://mprabhat.com/"> <errorCode>Code</errorCode> <errorMessage>Message</errorMessage> </faultBean> </ns1:MyException> </detail> </soap:Fault> </soap:Body> </soap:Envelope>
Brilliant everything works perfectly???? Wait let’s deploy it in WebSphere now. Please follow the same steps as described in previous post and then run with above input.
This is not to show demerit or loop hole in the spec or by the implementation provider, this is just another way of doing it but I would say follow the spec the chances of this not working is higher then the spec.
- If you provide both
getFaultInfo
andgetFaultBean
in aboveMyException
, you will find that control will always come togetFaultInfo
. So the spec is honored 🙂 - If in
MyExceptionBean
you remove getter and setters you will not see any Soap Fault but if you make your fieldspublic
it will again work ;), I know it’s simple Java bean specification.