Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How could we use @ExceptionHandler with spring web flux?

In spring web we could use annotation @ExceptionHandler for handling server and client errors for controllers.

I've tried to use this annotation with web-flux controller and it still worked for me, but after some investigation I've found out here

The situation with Spring Web Reactive is more complicated. Because the reactive streams are evaluted by a different thread than the one that executes the controllers method, the exceptions won’t be propagated to the controller thread automatically. This means that the @ExceptionHandler method will work only for exceptions that are thrown in the thread that handles the request directly. Exceptions thrown in the stream will have to be propagated back to the thread if we want to use the @ExceptionHandler feature. This seems like a bit of a let down but at the time of writing this Spring 5 is still not released so error handling might still get better.

So my question is how to propagate back exception to the thread. Is there a good example or article about using @ExceptionHandler and Spring web flux?

Updated: From spring.io it looks like it's supported, but still lack general understanding

Thanks,

like image 989
Evgen Avatar asked Mar 06 '18 18:03

Evgen


People also ask

Can I use Springmvc and WebFlux together?

Use Spring MVC with WebFlux to build Java-based web applications. Employ the various Spring MVC architectures. Work with controllers and routing functions. Build microservices and web services using Spring MVC and REST.

How do I collect exceptions in spring WebFlux?

3.2. There are three ways that we can use onErrorResume to handle errors: Compute a dynamic fallback value. Execute an alternative path with a fallback method. Catch, wrap and re-throw an error, e.g., as a custom business exception.

How do you use spring flux?

Spring WebFlux supports annotation-based configurations in the same way as the Spring Web MVC framework. To begin with, on the server, we create an annotated controller that publishes a reactive stream of the Employee resource. EmployeeRepository can be any data repository that supports non-blocking reactive streams.

What is the difference between ControllerAdvice and RestControllerAdvice?

The differences between @RestControllerAdvice and @ControllerAdvice is : @RestControllerAdvice = @ControllerAdvice + @ResponseBody . - we can use in REST web services. @ControllerAdvice - We can use in both MVC and Rest web services, need to provide the ResponseBody if we use this in Rest web services.


2 Answers

Now it is possible to use the @ExceptionHandler as well as @RestControllerAdvice or even @ControllerAdvice in Spring WebFlux.

Example:

  1. Add the webflux dependency

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    
  2. Create your class ExceptionHandler

    @RestControllerAdvice
    public class ExceptionHandlers {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionHandlers.class);
    
        @ExceptionHandler(Exception.class)
        @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
        public String serverExceptionHandler(Exception ex) {
            LOGGER.error(ex.getMessage(), ex);
            return ex.getMessage();
        }
    }
    
  3. Create a Controller

    @GetMapping(value = "/error", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public Mono<String> exceptionReturn() {
        return Mono.error(new RuntimeException("test error"));
    }
    

Example extracted here:

https://ddcode.net/2019/06/21/spring-5-webflux-exception-handling/

like image 124
Eddy Bayonne Avatar answered Oct 15 '22 01:10

Eddy Bayonne


You can use @ExceptionHandler annotated methods to handle errors that happen within the execution of a WebFlux handler (e.g., your controller method). With MVC you can indeed also handle errors happening during the mapping phase, but this is not the case with WebFlux.

Back to your exception propagation question, the article you're sharing is not accurate.

In reactive applications, the request processing can indeed hop from one thread to another at any time, so you can't rely on the "one thread per request" model anymore (think: ThreadLocal).

You don't have to think about exception propagation or how threads are managed, really. For example, the following samples should be equivalent:

@GetMapping("/test")
public Mono<User> showUser() {
  throw new IllegalStateException("error message!");
}


@GetMapping("/test")
public Mono<User> showUser() {
  return Mono.error(new IllegalStateException("error message!"));
}

Reactor will send those Exceptions as error signals as expected in the Reactive Streams contract (see the "error handling" documentation section for more on that).

like image 11
Brian Clozel Avatar answered Oct 15 '22 01:10

Brian Clozel