Global Exception Handling in Jersey - java

Is there a way to have global exception handling in Jersey? Instead of individual resources having try/catch blocks and then calling some method that then sanitizes all of the exceptions to be sent back to the client, I was hoping there was a way to put this where the resources are actually called. Is this even possible? If so, how?
Instead of, where sanitize(e) would throw some sort of Jersey-configured exception to the Jersey servlet:
#GET
public Object getStuff() {
try {
doStuff();
} catch (Exception e) {
ExceptionHandler.sanitize(e);
}
}
Having:
#GET
public Object getStuff() throws Exception {
doStuff();
}
where the exception would get thrown to something that I can intercept and call sanitize(e) from there.
This is really just to simplify all the Jersey resources and to guarantee that the exceptions going back to the client are always in some sort of understandable form.

Yes. JAX-RS has a concept of ExceptionMappers. You can create your own ExceptionMapper interface to map any exception to a response. For more info see: https://jersey.github.io/documentation/latest/representations.html#d0e6352

javax.ws.rs.ext.ExceptionMapper is your friend.
Source: https://jersey.java.net/documentation/latest/representations.html#d0e6665
Example:
#Provider
public class EntityNotFoundMapper implements ExceptionMapper<javax.persistence.EntityNotFoundException> {
public Response toResponse(javax.persistence.EntityNotFoundException ex) {
return Response.status(404).
entity(ex.getMessage()).
type("text/plain").
build();
}
}

All the answers above are still valid. But with latest versions of spring Boot consider one of below approaches.
Approach 1 :
#ExceptionHandler- Annotate a method in a controller with this annotation.
Drawback of this approach is we need to write a method with this annotation in each controller.
We can work around this solution by extending all controllers with base controller (that base controller can have a method annotated with #ExceptionHandler. But it may not be possible all the times.
Approach 2 :
Annotating a class with #ControllerAdvice and define methods with #ExceptionHandler
This is similar to Controller based exception (refer approach 1) but this is used when controller class is not handling the exception.
This approach is good for global handling of exceptions in Rest Api

Related

Controller advice in Spring MVC

I have some problems regarding Controller usage in Spring.
Preferably, I would like to keep the Controller methods small and simply use them to call a Service function as follows:
#Controller
class controllerClass {
#RequestMapping("/foo/")
public void foo(Model model) {
Data returnedData = fooServiceFunction();
model.addAttribute("data", returnedData);
}
}
#Service
class serviceClass {
fooServiceFunction() {
Data data = methodCall();
methodCall2();
methodCall3();
return data;
}
}
However, in practise I have found this implementation difficult because I have found myself needing to check if the methods called from within the fooServiceFunction() succeeded or failed. I have been returning a custom 'Status' class from these functions which is passed to the controller to signal if the methods have executed successfully and/or any errors that have occurred (validation errors, etc.).
Now, this is fine if I do not need to return any data. But if I want to return data from the Service function and pass it to the Controller, this would mean I would need to make a custom class for EVERY Controller method which would contain:
a) the data.
b) the success status
which just seems unreasonable.
I have considered just throwing Exceptions to indicate a failure, but this doesn't seem proper.
Is there a better way? What is the optimal way to handle these situations? Or should I just write fat Controller methods that implement more of the application/business logic?
Thank you.
I think the best approach would be to throw a custom exception and then use a class annotated with
#ControllerAdvice
to deal with that exception and make it return a ResponseEntity customized according to your needs. This way the line
return data;
will only occur if there are no exceptions

Bind Exception Handling to #ControllerAdvice class only

I have a controller class with REST methods that can throw various exceptions. I have decided to handle these exceptions in a separate class using the #ControllerAdvice and #ExceptionHandler for my handler methods.
However, I have the problem, that my REST methods use an annotation from another library. This library catches an exception that my REST method throws as well.
Now that I am handling the exceptions globally and not via try/catch in the REST method directly, my exception is always caught by the other library and not by my own handler method. Apparently, that other method in the library I am using wins due to the annotation.
How can I bind the exception handling to my own class to prevent it from being caught by anyone else?
My REST method:
#SomeLibraryAnnotation
#PostMapping(path = "/add", consumes = MediaType.APPLICATION_JSON_VALUE)
public HttpEntity< ? > addItem(#RequestHeader HttpHeaders headers, #RequestBody MyDTO myDTO)
throws UnsupportedOperationException {
doSomethingWith(myDTO);
return ResponseEntity.status(HttpStatus.CREATED).build();
}
My Exception Handler class:
#ControllerAdvice
public class MyExceptionHandler {
#ExceptionHandler(UnsupportedOperationException.class)
public ResponseEntity<?> handleUnsupportedOperationException(UnsupportedOperationException e) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(e.getMessage());
}
}
As the library method also catches the UnsupportedOperationException, it wins due to the #SomeLibraryAnnotation and the exception is never handled in my handler class.
You might try using #Order or #Priority in the MyExceptionHandler class, as discussed in Setting Precedence of Multiple #ControllerAdvice #ExceptionHandlers.
That would give Spring an opportunity to use your class instead of the one specified by the #SomeLibraryAnnotation. However, without knowing how Spring interprets that other annotation at context initialization, that's just a guess.
Did you tried to write #ExceptionHandler inside your controller? Like:
#RestController
#RequestMapping("/path")
public class TheController {
#ExceptionHandler(UnsupportedOperationException.class)
public ResponseEntity<?> handleUnsupportedOperationException(UnsupportedOperationException e) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(e.getMessage());
}
}
Maybe that would pickup and exception with higher priority. It's hard to answer not knowing what #SomeLibraryAnnotation is...
Those are simply Java Language rules, i.e. exception is no longer unhandled, as it was handled (caught in a catch block) by your other library. What you can do it is to re-throw (maybe conditionally) another exception in your library which caught original exception and see if #ExceptionHandler will handle it. It might not because #ExceptionHandler is handling exceptions thrown in Controller classes.
Second approach would be to throw exception which is only handled in #ExceptionHandler and then re-throw it be handled in other library.
In other words you need to choose where to handled first originally thrown exception.
Third approach would be use AOP interceptor #AfterThrowing or #Around and then execute whatever logic you want within.
Essence : There is no way to handle exception in two places at one time. Does it make sense?

Spring boot exception handling for specific annotated methods

Our spring boot controllers have methods called by ajax as well as the standard methods rendering CRUD templates. We'd like to be able to annotate all our ajax methods with a single annotation so that regardless of what type of exception is thrown, we can return a response the ui can handle.
I've been looking at the ControllerAdvice and ExceptionHandler annotations, but I don't think either can be used the way we intend. ControllerAdvice can only cover entire controllers, so any exception handling would also cover the non-ajax methods. Similarly, the ExceptionHandler annotation would handle exceptions from both types of methods.
The current idea is to split the two types of methods, ajax and CRUD, into separate controllers. Is there another way to do this?
I don't think this is that much easy/straightforward in Spring (or at least to my current spring knowledge).
We'd like to be able to annotate all our ajax methods with a single
annotation
Apart from separating ajaxMethods into another controller, I can think of another way of doing this.
1.Declare your own exception class like myAjaxException.
2.Don't handle this exception in controller, just throw it when you encounter any exception inside your ajax methods.
try{
//....
}catch(Exception ex){
throw new myAjaxException("this is myAjaxException blah blah blah");
}
3.Intercept myAjaxException by implementing HandlerExceptionResolver as below.
Any Spring bean declared in the DispatcherServlet’s application
context that implements HandlerExceptionResolver will be used to
intercept and process any exception raised in the MVC system and not
handled by a Controller.
public class AjaxExceptionResolver implements HandlerExceptionResolver {
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);
if (ex instanceof myAjaxException) {
//return response to UI
}
}

java class leve exception handling - catch exceptions of all methods in single place

I have a Java exception handling design question .
I have a Backing layer(java bean class) in my web app.
I would like to catch the exceptions(RunTimeE) thrown by all the methods in a class in single place. My backing bean class extends the AbstractBackingBean class.
Is there any way ,can i catch the exceptions from all the methods and log it in one place.
Yes. For a web application you can do that in a Filter:
public void doFilter(..) {
try {
chain.doFilter(req, resp);
} catch (Exception ex) {
// do something
}
}
If a filter is not an option for some reason, take a look at AOP. For example spring has good AOP support. It's similar to the filter approach, but you specify exactly which classes and methods you want to attach the handler to.

using multiple values HttpStatus in #ResponseStatus

I am using the Spring annotation #ResponseStatus in my Exception like
#ResponseStatus(value=HttpStatus.UNAUTHORIZED)
public class UnauthorizedException extends Exception{
}
Problem is I want to throw the same error for a number of values like HttpStatus.SC_SERVICE_UNAVAILABLE, etc..
Is there any way to use multiple values in #ResponseStatus? Thanks in advance.
No. You can't have multiple http status codes. Check http spec
If you actually want to set different status codes in different scenarios (but only one status code per response), then remove the annotation, and add it via code:
public X method(HttpServletResponse response) {
if (..) {
response.setStatus(..);
} else {
response.setStatus(..);
}
}
The only workaround that comes to mind is not using the #ResponseStatus annotation. Consider writing your own error handling code in the controller that catches the relevant exception sets the error code in the way you would prefer for that class. If it's in several controllers, consider writing an interceptor or using AOP.
You can set the response code in the HttpServletResponse class with the .setStatus() method, that you could get from the applicationContext.
Why not just create multiple exception classes and throw the appropriate one?

Categories

Resources