JAX-WS Exceptions and Faults: Annotation, Exception and Fault Handling Examples

0 Flares Twitter 0 Facebook 0 Google+ 0 LinkedIn 0 Email -- Filament.io 0 Flares ×

JAX-WS exception and SOAP fault handling sometimes confuses a Java programmer. This article explains the handling of JAX-WS exceptions and SOAP Fault with examples. Here, we also check some of the common Exceptions such as “IllegalAnnotationExceptions. java.lang.StackTraceElement does not have a no-arg default constructor.“. This article also discusses the JAX-WS mapping of WSDL faults to Java exceptions, Java exceptions to WSDL faults.
java JAX-WS exception fault handling example

Pre-Requisites

You should have a basic knowledge on how to create JAX-WS web services and clients. You may find the following articles helpful.

  1. Java JAX-WS Tutorial: Develop Web Services and Clients (Consumers) Using JAX-WS
  2. SOAP Binding: Difference between Document and RPC Style Web Services
  3. Logging or Tracing Web Service XML Request/Response with JAX-WS

 

More advanced features are discussed in the following articles

  1. JAX-WS Attachment – Enable MTOM for JAX-WS Web services
  2. JAX-WS Secure Web Services with Signatures and Encryption: WS-Security with Metro and WSIT
  3. Secure Metro JAX-WS UsernameToken Web Service with Signature, Encryption and TLS (SSL)

Development tools required:

  • Eclipse IDE
  • Metro (or JAX-WS) latest version distribution
  • JDK7
  • Tomcat 6 or above

Quick info on JAX-WS Fault Handing and Exception Handling

The JAX-WS Specification demands that mapped exception MUST be annotated with a javax.xml.ws.WebFault annotation. A wsdl:fault element is mapped to this Java exception A wsdl:fault element refers to a wsdl:message that contains a single part and is mapped to a Java bean, called a fault bean , which is just a POJO. The exception class should have two constructors and a getter method (to obtain fault details) as follows

WrapperException(String message, FaultBean faultInfo)
WrapperException(String message, FaultBean faultInfo, Throwable cause)
FaultBean getFaultInfo()

Where, WrapperException is the name of the Exception class and FaultBean is the fault bean POJO.

The cause of JAX-WS Exceptions “IllegalAnnotationExceptions. java.lang.StackTraceElement does not have a no-arg default constructor”

Sometimes when you execute the “wsgen” tool to generate the web service artifacts you may encounter the following error, if you don’t implement JAX-WS exceptions and fault properly.

…………………………………..
Caused by: java.security.PrivilegedActionException: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
java.lang.StackTraceElement does not have a no-arg default constructor.
	this problem is related to the following location:
		at java.lang.StackTraceElement
		at public java.lang.StackTraceElement[] java.lang.Throwable.getStackTrace()
		at java.lang.Throwable
		at private java.lang.Throwable[] com.globinch.ws.jaxws.MyServiceExceptionBean.suppressed
		at com.globinch.ws.jaxws.MyServiceExceptionBean

	at java.security.AccessController.doPrivileged(Native Method)
	at com.sun.xml.ws.model.AbstractSEIModelImpl.createJAXBContext(AbstractSEIModelImpl.java:148)
	………………..

One possible reason for this error is, invalid use of custom exception in your JAX-WS web service implementations. This is because, Exceptions and Errors which are of “Throwable” objects cannot be serialized to XML because StackTraceElement doesn’t have a no-arg constructor. The no argument constructor is required by the JAXB runtime to generate the artifacts. You may be able to fix this by using @WebFault annotation on your exception class and by providing a FaultBean. Any Exception/Throwable class cannot be marshalled by JAXB due to the fact that StackTraceElement does not have a default constructor.
Another possible solution is to use @XmlTransient annotation on overridden methods that use StackTrace. The JAXB 2.2.5 and above versions will process the @XmlTrasient annotation in your custom class.

JAX-WS Exception Handling and JAX-WS SOAP Fault Handling Example

Now, let us create a web service and custom exception class to handle JAX-WS exception and SOAP faults.

Web Service SEI and Implementation Classes

The SEI interface has just one method greetMe() which accepts a name parameter and throws a custom MyServiceException exception.
/*
 * @(#)MyService.java
 * @author Binu George
 * Globinch.com
 * copyright http://www.globinch.com. All rights reserved.
 */
package com.globinch.ws;

import javax.jws.WebMethod;
import javax.jws.WebService;

/**
 * The web service SEI.
 * 
 * @author Binu George
 * @since 2013
 * @version 1.0
 */
@WebService
public interface MyService {

	@WebMethod
	public String greetMe(String name) throws MyServiceException;
}

In the implementation class, the greetMe() web service method throws MyServiceException if the incoming name if “fault”. Otherwise the service method returns a greeting message to the consumer.

/*
 * @(#)MyServiceImpl.java
 * @author Binu George
 * Globinch.com
 * copyright http://www.globinch.com. All rights reserved.
 */
package com.globinch.ws;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

/**
 * The web service implementation class.
 * 
 * @author Binu George
 * @since 2013
 * @version 1.0
 */
@WebService(serviceName="MyService", portName="MyServiceService")
public class MyServiceImpl implements MyService {

	/**
	 * 
	 */
	public MyServiceImpl() {
		

	}

	/* (non-Javadoc)
	 * @see com.globinch.ws.MyService#greetMe(java.lang.String)
	 */
	@WebMethod
	
	public String greetMe(@WebParam(name="name") String name) throws MyServiceException {
		if(name.equalsIgnoreCase("fault")){
			MyServiceFault fault = new MyServiceFault();
			fault.setFaultCode("1234");
			fault.setFaultString("My Service Error");
			throw new MyServiceException("1234","My Service Error");
		}else{
			return "Hello "+name;
		}
		//return "Hello "+name;
	}

}

The Fault Bean.

This is the fault bean POJO class required by the JAXB runtime to process exceptions.

/*
 * @(#)MyServiceFault.java
 * @author Binu George
 * Globinch.com
 * copyright http://www.globinch.com. All rights reserved.
 */
package com.globinch.ws;

/**
 * The MyServiceFault class.
 * 
 * @author Binu George
 * @since 2013
 * @version 1.0
 */
public class MyServiceFault {
	/**
	 * Fault Code
	 */
	 private String faultCode;
	 /**
	  * Fault String
	  */
     private String faultString;
	/**
	 * @return the faultCode
	 */
	public String getFaultCode() {
		return faultCode;
	}
	/**
	 * @param faultCode the faultCode to set
	 */
	public void setFaultCode(String faultCode) {
		this.faultCode = faultCode;
	}
	/**
	 * @return the faultString
	 */
	public String getFaultString() {
		return faultString;
	}
	/**
	 * @param faultString the faultString to set
	 */
	public void setFaultString(String faultString) {
		this.faultString = faultString;
	}
	
}

Custom Exception class.

This class is required to be annotated with @WebFault annotation.

/*
 * @(#)MyServiceException.java
 * @author Binu George
 * Globinch.com
 * copyright http://www.globinch.com. All rights reserved.
 */
package com.globinch.ws;

import javax.xml.ws.WebFault;

/**
 * The MyServiceException class.
 * 
 * @author Binu George
 * @since 2013
 * @version 1.0
 */
@WebFault(name="MyServiceFault",targetNamespace="http://ws.globinch.com/")
public class MyServiceException extends Exception {

	
	/**
	 * 
	 */
	private static final long serialVersionUID = -6647544772732631047L;
	private MyServiceFault fault;
	/**
	 * 
	 */
	public MyServiceException() {
		// TODO Auto-generated constructor stub
	}
	/**
	 * 
	 * @param fault
	 */
	protected MyServiceException(MyServiceFault fault) {
        super(fault.getFaultString()); 
        this.fault = fault;
     }
	/**
	 * 
	 * @param message
	 * @param faultInfo
	 */
	public MyServiceException(String message, MyServiceFault faultInfo){
		super(message);
        this.fault = faultInfo;
	}
	/**
	 * 
	 * @param message
	 * @param faultInfo
	 * @param cause
	 */
	public MyServiceException(String message, MyServiceFault faultInfo, Throwable cause){
		super(message,cause);
        this.fault = faultInfo;
	}
	/**
	 * 
	 * @return
	 */
	public MyServiceFault getFaultInfo(){
		return fault;
	}
	
	/**
	 * @param message
	 */
	public MyServiceException(String message) {
		super(message);
		// TODO Auto-generated constructor stub
	}
	/**
	 * @param message
	 */
	public MyServiceException(String code, String message) {
		super(message);
		this.fault = new MyServiceFault();
	    this.fault.setFaultString(message);
	    this.fault.setFaultCode(code);
	}

	/**
	 * @param cause
	 */
	public MyServiceException(Throwable cause) {
		super(cause);
		// TODO Auto-generated constructor stub
	}

	/**
	 * @param message
	 * @param cause
	 */
	public MyServiceException(String message, Throwable cause) {
		super(message, cause);
		// TODO Auto-generated constructor stub
	}

}

You can create the WSDL of the above service, by using the “wsgen” tool or the web container will create one for you, if you package and deploy the service to a web container such as tomcat. Read the below article to know more about how to do that.
Java JAX-WS Tutorial: Develop Web Services and Clients (Consumers) Using JAX-WS

WSDL and Schema files

The WSDL should look like the following.




  
    
      
    
  
  
    
  
  
    
  
  
    
  
  
    
      
      
      
    
  
  
    
    
      
      
        
      
      
        
      
      
        
      
    
  
  
    
      
    
  

And the XML schema is below.




  

  

  

  
    
      
    
  

  
    
      
    
  

  
    
      
      
    
  

As we discussed above, the wsdl:fault element is mapped to our exception class MyServiceException. A wsdl:fault element refers to a wsdl:message that contains a single part and is mapped to a Java bean, called a fault bean , which is our MyServiceFault class.

JAX-WS exception handling example request and response

Now you can execute the service method greetMe() using a test class or tool such as SOAP UI. Let us first send a proper name as the request. The MyService response will greet you back.
Request


   
   
      
          Binu George
      
   

Response


   
      
         Hello Binu George
      
   

Now let us send the name as “fault” so that the service throws an excpetion with a erro code and error message.

Request


   
   
      
          fault
      
   

Response


   
      
         S:Server
         My Service Error
         
            
               1234
               My Service Error
            
         
      
   

You can see the response with proper fault code and fault message. The fault details gives the details of error as supplied by the web service method greetMe(). You may have to disable -Dcom.sun.xml.ws.fault.SOAPFaultBuilder.disableCaptureStackTrace to avoid printing stacktrace as part of the response.
The above examples source files are not optimized or production ready. These are created just for learning purposes.

References

0 Flares Twitter 0 Facebook 0 Google+ 0 LinkedIn 0 Email -- Filament.io 0 Flares ×

Related Posts

This Post Has 8 Comments

  1. Hi, I followed your example (and other that I found on the net) but I’m still unable to have custom exceptions in my web services.
    I’m using Netbeans 7.3.1 to develop, deploy and run my web application. The server is glassfish 4.0 the JavaEE and the JDK that I choose for the netbeans project are JEE5 and JDK7.
    When I try to invoke the greetMe method of your example with a string as parameter all works properly but if I pass the String “fault” as parameter, I receive the following exception:
    WS00041: Service invocation threw an exception with message : null; Refer to the server log for more details
    Exceptions details : java.lang.reflect.InvocationTargetException
    javax.servlet.ServletException: java.lang.reflect.InvocationTargetException at org.glassfish.webservices.monitoring.WebServiceTesterServlet.doPost(WebServiceTesterServlet.java:336) at org.glassfish.webservices.monitoring.WebServiceTesterServlet.invoke(WebServiceTesterServlet.java:106) at org.glassfish.webservices.JAXWSServlet.doPost(JAXWSServlet.java:157) at javax.servlet.http.HttpServlet.service(HttpServlet.java:707) at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:318) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160) at […]
    What can be wrong?
    Thanks in advance.

  2. EDIT MY PREVIOUS MESSAGE:
    I tried to use TCPMon to send and receive the SOAP message to the web server and all works fine, so your example is correct.
    The error is on the client side, probably the generator of the class from WSDL doesn’t work well.
    This is the exception that the web service client throws when the webServer send a fault message:

    Exception in thread “main” java.lang.ExceptionInInitializerError
    at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:107)
    at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:78)
    at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(SEIStub.java:129)
    at com.sun.proxy.$Proxy32.greetMe(Unknown Source)
    at testclientws.TestClientWS.greetMe(TestClientWS.java:28)
    at testclientws.TestClientWS.main(TestClientWS.java:18)
    Caused by: java.lang.ClassCastException: com.sun.xml.bind.v2.runtime.JAXBContextImpl cannot be cast to com.sun.xml.internal.bind.api.JAXBRIContext
    at com.sun.xml.internal.ws.fault.SOAPFaultBuilder.(SOAPFaultBuilder.java:550)
    … 6 more
    Java Result: 1

  3. EDIT/SOLVED:
    It was a library problem. I tried to add the JAX_WS 2.2.6 libraries on the client and all works fine.
    Sorry for the multiple posts.
    Thanks a lot for your example.

  4. Hi Guiseppe,
    Glad to hear that the problem is solved. I was little busy with my regular job and could not reply you promptly.

    Thank You
    Binu George

  5. Thanks for the great article. Just one point: the code that sets up the fault in the greetMe() implementation is not needed, since it isn’t actually used and the constructor for the exception creates the fault internally. Alternative, a different constructor can be used in greetMe; the constructor that passes a fault.

  6. Hi Binu, I’ve been working with jax-ws for a while and have encountered an issue which you or someone who follows your blog, might be able to shed some light on. I’ve had no problems running the code in this example, but when I add a wsdl policy requiring (Mutual Certificate Security) the signing of the request and response payloads I’m encountering a problem with signing SOAP Faults.

    When the service returns normally (ie: when it doesn’t throw a SOAP Fault), the response is signed correctly, and the client has no problem validating the signature. However, when I throw an exception and return a SOAP Fault (which I also enforce signing for), the client throws a WSSecurityException stating “the signature or decryption was invalid”. Have you ever encountered this issue?

    I would be grateful for any help/suggestions.

  7. Great site you have got here.. It’s difficult to find high-quality writing like yours these days.
    I seriously appreciate people like you! Take care!!

  8. Why to use Fault Action Annotation ? why can’t we just simply throws MyException in webservice method?In both cases WSDL generated is same then why to use @WebFault annotation ?

Leave a Reply

Your email address will not be published. Required fields are marked *

Paged comment generated by AJAX Comment Page
© 2024 Globinch Java Forum - Theme by WPEnjoy · Powered by WordPress