15

In the code below, when the endpoint getPerson gets hit, the response will be a JSON of type Person. How does Spring convert CompletableFuture<Person> to Person?

@RestController
public class PersonController {

    @Autowired
    private PersonService personService;


    @GetMapping("/persons/{personId}" )
    public CompletableFuture<Person> getPerson(@PathVariable("personId") Integer personId) {

        return CompletableFuture.supplyAsync(() -> personService.getPerson(personId));
    }
}
Ken Chan
  • 84,777
  • 26
  • 143
  • 172
MA1
  • 926
  • 10
  • 28
  • You'd have to check the source, but presumably it does a `thenApply` to retrieve the eventual result and send it back to the client. – Thilo Oct 22 '19 at 13:49

1 Answers1

23

When the CompletableFuture is returned , it triggers Servlet 3.0 asynchronous processing feature which the execution of the CompletableFuture will be executed in other thread such that the server thread that handle the HTTP request can be free up as quickly as possible to process other HTTP requests. (See a series of blogpost start from this for detailed idea)

The @ResponseBody annotated on the @RestController will cause Spring to convert the controller method 's retuned value (i.e Person) through a HttpMessageConverter registered internally. One of its implementation is MappingJackson2HttpMessageConverter which will further delegate to the Jackson to serialise the Person object to a JSON string and send it back to the HTTP client by writing it to HttpServletResponse

Ken Chan
  • 84,777
  • 26
  • 143
  • 172
  • How is Person java object extracted from CompletableFutere under the hood? Is that happening by calling join method? – MA1 Oct 24 '19 at 19:59
  • No . It will be adapted to the Spring 's `DeferredResult` . But from the `CompletableFutere` point of view , it just setup the processing pipeline by using `CompletableFutere.handle()` which will populated the `Person` to `DeferredResult` – Ken Chan Oct 25 '19 at 02:52
  • Is there any way I can access the code that spring uses inside handle method? I'm looking for the way that spring handles the exceptions inside handle method. Does it wrap it into `CompletionException` or just throw the exception as is? The reason I'm asking is because I'm seeing two different behaviors for two different spring applications with different java versions. @Ken – MA1 Oct 25 '19 at 11:58
  • Do you mean you want to use your own code to handle the exception thrown from the `CompletableFutere`? If yes, you can checkout implementing a `DeferredResultProcessingInterceptor` 's `handleError()` method – Ken Chan Oct 25 '19 at 15:58
  • I mean I want to see the implementation code that is passed to handle method that spring uses to get Person object from `CompletableFuture` @Ken – MA1 Oct 25 '19 at 16:02
  • Just an additional question: Is it sufficient to leave out the `Async` Annotation on the controller? Usually you decorate async methods with `Async`. – Thomas Lang Nov 07 '22 at 07:43