Custom Exception Handling/Error Handling in Spring - java

My Application - Java 1.6, Spring 3.1.2, Hibernate 4.1.1, Thymeleaf 2.0.15
Currently in my application, there is no any exception/error handling mechanism is implemented. I handling exceptions in ordinary cultural way. But now I need to introduce a "Robust Error Handling Mechanism". Please suggest me to implement Custom Error/Exception Handling mechanism with Example.
Thanks and appriciate from experts like you.

I'll make as an answer its easier to format. When you say "But I need to implement some Generalized Custom Exception so that same Exception could be thrown acrross the application." Its how I understood it and something that #ControllerAdvice is directly handling, but it applies only to Controllers. Than again, all you lower layers can declare throws on the method, and delegate it to Controller for exception handling. As an example, the following would be the error handling controller handling your custom exception
#ControllerAdvice
public class GlobalErrorHandler {
#ExceptionHandler(value = VermaException.class)
#ResponseBody
public String heightError(VermaException ex) {
return "error";
}
}
Your exception
public class VermaException extends Exception {
}
now whenever the the exception is thrown from the controller class, it will be captured and handled in your GlobalErrorHandler.
Again pasting the reference http://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
UPDATE after comment
#ControllerAdvice is added in the version 3.2, for the earlier version you can have a CommonController extended by your controller, containing the error handler methods e.g. per Controller solution
#Controller
public class CommonController {
#ExceptionHandler
public #ResponseBody String handle(VermaException e) {
return "error";
}
}
an extending contorller
#Controller
public class ExceptionController extends CommonController {
#RequestMapping("/exception")
public #ResponseBody String exception() {
throw new VermaException();
}
}

Related

SPRING BOOT - Handle HttpClientErrorException using #ControllerAdvice

I have a Spring Boot Java application. There is a service class that throws a "401 Unauthorized" HttpClientErrorException since the access token used in the application has expired. I want to handle this exception globally for which I have used the #ControllerAdvice annotation.
The error is:
Caused by: org.springframework.web.client.HttpClientErrorException: 401 Unauthorized
The class is:
#Slf4j
#EnableWebMvc
#ControllerAdvice(basePackages = Service.class)
public class HttpClientErrorHandler{
#ExceptionHandler(HttpClientErrorException.class)
#ResponseStatus(HttpStatus.UNAUTHORIZED)
public String errorHandle(HttpClientErrorException e) {
log.error("log HttpClientErrorException: ", e);
return "HttpClientErrorException_message";
}
}
Since the exception was caused in the service class, I have mentioned it specifically in the basePackages. The entire configuration for the program is specified in the application.yml file. I have not used the xml configuration. I don't understand why the #ControllerAdvice annotation is not working. The program still throws the exception. Can someone explain?
#ControllerAdvice(basePackages = Service.class)
The exception is bubbled to #Controller class, and #ControllerAdvice is supposed to apply to controller, so you should set basePackageClasses to your controller package instead of your service package.
By default, #ControllerAdvice is applied to all Controller so you can remove the basePackageClasses unless you want to narrow down the controller advise
I had also faced similar issue,
try adding #Order(Ordered.HIGHEST_PRECEDENCE) below #ControllerAdvice.
We add it to get priority over Spring's default DefaultHandlerExceptionResolver. To understand more about why we add it read this answer.
Also no need to give base packages, it will consider all packages by default.
To handle exception of any other type you can include below existing exception handler for HttpClientErrorException you already have written,
#ExceptionHandler(Exception.class)
public Strring handleAnyExceptions(Exception ex) {
return "your message";
}
Hope it helps !

Spring MVC: Predefined exception classes?

In JAX-RS I have several exceptions extending WebApplicationException, for example NotAuthorizedException and NotFoundException. These are mapped to the corresponding HTTP status codes, so for basic use cases I can just throw instances of these exceptions.
In Spring MVC I noticed that I have to write my own exception classes, and add the corresponding #ResponseStatus annotations:
#ResponseStatus(HttpStatus.UNAUTHORIZED)
private class NotAuthorizedException extends RuntimeException {
NotAuthorizedException(String message) {
super(message);
}
}
Is there a simpler way? Do pre-defined exception classes exist?

Java - spring console application global exception handler

Java - spring - quartz application
I have Java application with spring 3.x which use quartz scheduler to process some data.
I was looking at the following article where they defined global Global Servlet container exception handler
I want to to configure spring to catch any exception occur into my application.
Above mentioned article uses "org.springframework.web.servlet.handler.HandlerExceptionResolverComposite" it is servlet speicfic implementation that's why i can't use it.
any help is appreciated.
You did not mention what you want to do when an exception is caught. If you just want to log the exception, you could use AOP for that.
A probably simpler solution would be to wrap your tasks with a class that catches the exception.
The class you mention is used in a catch block in the Spring MVC DispatcherServlet for matching specific Exceptions to handlers. AFAIK there isn't a class to do this out-of-the-box with vanilla Spring, but there's no reason you couldn't create a similar execution container for your app:
public interface ExceptionHandler {
public void handle(Exception e);
}
public class ExecutionEnvironment {
private Map<Class, ExceptionHandler> executionHandlers;
public void run() {
try {
// Your app code...
} catch (Exception e) {
if(executionHandlers.get(e.getClass()) != null) {
executionHandlers.get(e.getClass()).handle(e);
} else {
throw new RuntimeException(e);
}
}
}
}
Then use a context configuration to set up your exception handlers. Hope this helps.

Spring annotations: Is there a similar annotation like #ExceptionHandler used in Controller stereotypes for #Repository or #Service stereotypes?

I tried to see if I could use org.springframework.web.bind.annotation.ExceptionHandler in a Repository out of curiosity. As expected the annotation is ignored.
I have a low priority instrumentation service that I don't want exceptions to bubble up from. Rather than coding each method on the instrumentation service with a try/catch I would have liked to have a #ExceptionHandler method for the service - similar to technicques used in a Spring #Controller.
Thoughts?
I do not think that you can get this from Spring right now (perhaps you want to make a feature request...), but you should be able to do this pretty easily with Spring AOP.
#Aspect
public class DaoAspect {
#AfterThrowing(/*any method in a #Repository class that is not annotated with #ExceptionHandler*/ throwing="ex")
public void doRecoveryActions(DataAccessException ex) {
//find method of throwing class that can handle the exception via #ExceptionHandler
}
}

JAX-WS - Map Exceptions to faults

I am using JAX WS to expose a WebService. Some of the operations of this service can generate exceptions. Not internal server exceptions, but rather exceptions that are dependent on the input arguments of the operation invocation.
If I specify that my operation throws a custom Exception, like so:
#WebService
#SOAPBinding(style = Style.RPC, use = Use.LITERAL)
public class MyServiceEndpointImpl implements MyServiceEndpoint {
#WebMethod
public void throwsException throws InvalidInputException;
}
I end up with the following stacktrace when running the application:
com.sun.xml.ws.model.RuntimeModelerException: runtime modeler error: Wrapper class com.mypackage.ws.services.jaxws.InvalidInputExceptionBean is not found. Have you run APT to generate them?
at com.sun.xml.ws.model.RuntimeModeler.getClass(RuntimeModeler.java:285)
at com.sun.xml.ws.model.RuntimeModeler.processExceptions(RuntimeModeler.java:1006)
at com.sun.xml.ws.model.RuntimeModeler.processRpcMethod(RuntimeModeler.java:969)
at com.sun.xml.ws.model.RuntimeModeler.processMethod(RuntimeModeler.java:546)
at com.sun.xml.ws.model.RuntimeModeler.processClass(RuntimeModeler.java:370)
at com.sun.xml.ws.model.RuntimeModeler.buildRuntimeModel(RuntimeModeler.java:256)
at com.sun.xml.ws.server.EndpointFactory.createSEIModel(EndpointFactory.java:322)
at com.sun.xml.ws.server.EndpointFactory.createEndpoint(EndpointFactory.java:188)
at com.sun.xml.ws.api.server.WSEndpoint.create(WSEndpoint.java:467)
at org.jvnet.jax_ws_commons.spring.SpringService.getObject(SpringService.java:333)
at org.jvnet.jax_ws_commons.spring.SpringService.getObject(SpringService.java:45)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport$1.run(FactoryBeanRegistrySupport.java:121)
Adding #XmlRootEntity to InvalidInputException does not solve the problem.
If this is not the recommended way to report faults over web services, then is there a better way? Should my exceptions inherit from RuntimeException and rely on the transport for the error handling (i.e., everything will end up wrapped in a SOAPException)? I was hoping for something like Spring-WS' SoapFaultAnnotationExceptionResolver. Is there something similar at all available for JAX-WS?
Did you try to annotate your exception with #WebFault? Also, do you implement getFaultInfo()?
EDIT: I realize my answer was maybe not detailed enough. As reminded in this thread (for example):
The JAX-WS 2.0 specification demands
that the exception annotated with
#WebFault must have two constructors
and one method [getter to obtain the fault information]:
WrapperException(String message, FaultBean faultInfo)
WrapperException(String message, FaultBean faultInfo, Throwable cause)
FaultBean getFaultInfo()
The WrapperException is replaced by
the name of the exception, and
FaultBean is replaced by the class
name that implements the fault bean.
The fault bean is a Java bean that
contains the information of the fault
and is used by the Web service client
to know the cause for the fault.
This is detailed in section 2.5 Fault of the JAX-WS specification. Does your exception conform to this? Can you post the code?
The OP is right. As per specification 2.1, section 3.7 Service Specific Exception, it is not required to use the #WebFault annotation, JAX-WS can generate the wrapper beans dynamically for exceptions that do not match the pattern described in section 2.5 (just provide a getter for the information you want to be present in the fault). For exceptions that match the pattern described in section 2.5 (i.e. exceptions that have a getFaultInfo method and #WebFault annotation), the FaultBean is used as input to JAXB when mapping the exception to XML Schema.
So the solution suggested above (matching the pattern described in section 2.5) is only a workaround. The generation of wrapper beans should just work for other exceptions. And I don't know why this fails here.
An addition to the answer above. I ended up with this as my InvalidInputException implementation:
#WebFault(faultBean = "com.mypackage.ws.exception.FaultBean")
public class InvalidInputException extends Exception {
private static final long serialVersionUID = 1L;
private FaultBean faultBean;
public InvalidInputException() {
super();
}
public InvalidInputException(String message, FaultBean faultBean, Throwable cause) {
super(message, cause);
this.faultBean = faultBean;
}
public InvalidInputException(String message, FaultBean faultBean) {
super(message);
this.faultBean = faultBean;
}
public FaultBean getFaultInfo() {
return faultBean;
}
}
And FaultBean is just a simple POJO with currently no data at all. Now, according to the JAX-WS specification (see 3.7 Service Specific Exception), it conforms to what is required of an exception annotated with #WebFault, so it will not create a wrapper bean for it, which probably is what was failing.
This is a decent workaround, but it does not explain the error in the question.

Categories