How can I make the controllerAdvice class catch the exception that is thrown from completablefutrue.
In the code below I have a method checkId
that throws a checked exception. I call this method using completablefuture and wrap the checked exception inside CompletionException. Although I have a handler method in controller advice class, but it didn't handle the error.
package com.example.demo.controller;
@RestController
public class HomeController {
@GetMapping(path = "/check")
public CompletableFuture<String> check(@RequestParam("id") int id) {
return CompletableFuture.supplyAsync(() -> {
try {
return checkId(id);
}
catch (Exception e) {
throw new CompletionException(e);
}
});
}
public String checkId(int id) throws Exception {
if (id < 0) {
throw new MyException("Id must be greater than 0");
}
return "id is good";
}
}
-
package com.example.demo;
public class MyException extends Exception {
public MyException(String message) {
super(message);
}
}
-
package com.example.demo;
@ControllerAdvice
public class ExceptionResolver {
@ExceptionHandler(value = CompletionException.class)
public String handleCompletionException(CompletionException ex) {
return ex.getMessage();
}
}
--
package com.example.demo;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Stack trace:
com.example.demo.MyException: Id must be greater than 0
at com.example.demo.controller.HomeController.checkId(HomeController.java:30) ~[classes/:na]
at com.example.demo.controller.HomeController.lambda$0(HomeController.java:19) ~[classes/:na]
at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1700) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1692) ~[na:na]
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290) ~[na:na]
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020) ~[na:na]
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656) ~[na:na]
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594) ~[na:na]
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177) ~[na:na]
2020-01-24 14:38:30.489 ERROR 938 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is com.example.demo.MyException: Id must be greater than 0] with root cause
com.example.demo.MyException: Id must be greater than 0
at com.example.demo.controller.HomeController.checkId(HomeController.java:30) ~[classes/:na]
at com.example.demo.controller.HomeController.lambda$0(HomeController.java:19) ~[classes/:na]
at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1700) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1692) ~[na:na]
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290) ~[na:na]
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020) ~[na:na]
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656) ~[na:na]
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594) ~[na:na]
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177) ~[na:na]
@Deadpool and I were able to identify the problem.
Inside the catch block in the completableFuture code, the exception is wrapped inside CompletionException
exception which is a run-time exception. When the endpoint gets hit, at some point the CompletionException
exception gets unwrapped to the original exception which is of type MyException
(the checked exception). Which means the handler method should handle an exception of type MyException
instead of CompletionException
.
@ExceptionHandler(value = MyException.class)
@ResponseBody
public String handleCompletionException(MyException ex) {
return ex.getMessage();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With