简体   繁体   中英

How to catch exceptions with the CompletableFuture class in REST web services and Spring?

I have developed some async web services with spring framework and REST, I have consumed it from a client created with spring class AsyncRestTemplate . Class return an object ListenableFuture<ResponseEntity<T>> (with the method getForEntity ), which brings the value returned by the web service (with the method .get():<T> ) . It works fine, however when occurs an custom exception in the REST web service (which extends RuntimeException class) the client does not catch it correctly and it show me the follow message:

"timestamp": "2018-05-28T14:25:15.393+0000", "status": 500,
"error": "Internal Server Error", "message": "java.util.concurrent.ExecutionException: org.springframework.web.client.HttpServerErrorException: 500 null",
"path": "/client/result"

Does someone knows how can i solve the problem?. I want the client shows me the custom exception message.

The server codes are the following:

Configuration Class:

@Configuration
@EnableAsync
public class ConfigurationClass {
    @Bean
    public Executor threadPoolTaskExecutor() {
        return new ThreadPoolTaskExecutor();
    }
}

Controller class:

@RestController
@RequestMapping("/server")
public class ControllerClass {

    @GetMapping("/start")
    @Async
    public CompletableFuture<String>  callService() throws InterruptedException{
        Thread.sleep(10000L);
        if(true)
            throw new RuntimeException("Custom Error");
        return CompletableFuture.completedFuture("OK");
    }
}

The client code (consumer) is the following:

@RestController
@RequestMapping("/client")
public class ControllerClass {

    private ListenableFuture<ResponseEntity<String>> entity;

    @GetMapping("/start")
    @Async
    public void callService() throws InterruptedException {
        AsyncRestTemplate restTemplate = new AsyncRestTemplate();
        entity = restTemplate.getForEntity("http://localhost:8080/server/start",
                 String.class);
    }

    @GetMapping("/state")
    public boolean getState() {
        try {
            return entity.isDone();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @GetMapping("/result")
    public ResponseEntity<String> getResult() {
        try {
            return entity.get();

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

Thanks for your help, Regards.

Is was added 19/05/2018---------------------------------------

I'm close to the solution. In the control class of web service I added the method annotated with @ExceptionHandler ,Like in the follows code:

@ExceptionHandler(RuntimeException.class)
    void handleIllegalArgumentException(HttpServletResponse response) throws IOException {
        response.sendError(200, "custom Error");
    }

It works fine, the client has already recognized the exception correctly, however, if I change the status by other in the web service (like 201, 400, 401, which are HTTP valid status ), I go back to get the message "java.util.concurrent.ExecutionException: org.springframework.web.client.HttpServerErrorException: 500 null" , in the client.

Does someone knows the reason?

When RestTemplate receives a 4xx or 5xx response code, it considers it as an error and throws a HttpClientErrorException / HttpServerErrorException , instead of returning a ResponseEntity .

For your use case, you can set an error handler (extending from DefaultResponseErrorHandler ) which does not consider 4xx and 5xx responses as errors.

Instead of

AsyncRestTemplate restTemplate = new AsyncRestTemplate();

use the following code

    AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate();
    asyncRestTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
        @Override
        protected boolean hasError(HttpStatus statusCode) {
            return false;
        }
    });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM