0

I'm working on a microservice app, in service layout I want to invoke with CompletableFuture.runAsync(). The problem is when I want to throw exception, I have my own Handler Exception, but I can't capture error when it is produced in my catch block inside CompletedFuture shown below:

Controller:

@PostMapping(path="/offers/offer")
    public CompletableFuture<Oferta> infoPropiedad(@Valid @RequestBody OfertaRequest inDTO) throws 
    WebServiceBadResponseException, SOAPException, IOException, InterruptedException, ExecutionException  {
        System.out.println("THREAD: "+Thread.currentThread().getName());
        CompletableFuture<Oferta> outTO = new CompletableFuture<Oferta>();
        
        return CompletableFuture.supplyAsync(()->{
            try {
                return ofertasService.ofertasService(inDTO);
            } catch (Exception e) {
                System.out.println("Error inesperado en la capa del controlador");
            }
            return null;
        });
    }

Service:

CompletableFuture<OfertaCrm> completableFutureCRM = 
                CompletableFuture.supplyAsync(()->  {
                    try {
                        return clientOferta.llamadaWebServiceOfertas(inDTOCrm);
                    } catch (Exception e1) {
                        //throw Exception and capture it with my handler class
                    }
                });

ClientWs:

    public OfertaCrm llamadaWebServiceOfertas(OfertaRequestCRM inDtoCrm) 
            throws SOAPException, IOException {

                CompletableFuture<OfertaCrm> completableFuture = new CompletableFuture<OfertaCrm>();
                
                logger.info("Iniciamos la llamada al WS");
//Error produces here and I want to controle it and capture with my handler class

Error handler:

@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler({
        WebServiceBadResponseException.class,
        SOAPException.class,
        IOException.class
    })
    @ResponseBody
    public ErrorMessage internalError(Exception exception) {
        return new ErrorMessage(exception,exception.getMessage());
    }

I could not be applying the correct form. Any idea how to throw the exception inside the supplyAsync block?

balias
  • 499
  • 1
  • 4
  • 17
  • Maybe [this answer](https://stackoverflow.com/a/43767613/2711488) is helpful… – Holger Oct 04 '21 at 14:59
  • Thank you but is not what I am searching, I need when the exception throw my handler control this exception and return a body response formy endpoint, I don't know if I don't understand completable future functionality but I need answer in my current code. Thank for try to help me :) – Alejandro Martin Oct 04 '21 at 15:06

1 Answers1

0

CompletableFuture will wrap the exception thrown within the execution inside a CompletionException. You can handle it by intercepting the root cause exception directly. Below is a simplified example.

Controller:

@RestController
public class SimpleController {
    @Autowired
    SimpleService simpleService;

    @GetMapping("/testing")
    public CompletableFuture<Integer> testing(){
        return simpleService.doStuff();
    }
}

Service:

@Service
public class SimpleService {

    public CompletableFuture<Integer> doStuff(){
        // 1 / 0 will throw ArithmeticException
        return CompletableFuture.supplyAsync(() -> 1 / 0);
    }
}

Controller Advice:

@RestControllerAdvice
public class SimpleControllerAdvice {

    @ExceptionHandler(ArithmeticException.class)
    public String handleCompletionException(ArithmeticException ex){
        return "hello world";
    }
}

GET /testing
hello world

Sam Jing Wen
  • 63
  • 1
  • 6