3

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.

YourReflection
  • 375
  • 7
  • 22

3 Answers3

0

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.

theonlyrao
  • 416
  • 2
  • 13
  • Thanx for the answer. I already tried both annotations. But it didn't work. I think they only work if I have multiple classes with ControllerAdvice annotations to prioritize them. But they do not have any effect if I use some custom annotation of a library that happens to catch the same exceptions. – YourReflection Feb 12 '19 at 17:50
0

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...

Marius Jaraminas
  • 813
  • 1
  • 7
  • 19
0

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?

fg78nc
  • 4,774
  • 3
  • 19
  • 32