Spring AsyncRestTemplate is now Deprecated

As part of the Spring 5.0 release, a large number of the Asynchronous HTTP classes have been deprecated in favor of Spring’s new reactive ClientRequest and WebClient classes. Here is a before and after on how you can update your RestTemplate code to the latest non-deprecated way of performing API calls in Spring.

Deprecated AsyncRestTemplate Example

Here is an example of an asynchronous implementation using Spring’s AsyncRestTemplate in Spring v4 and below:


@Autowired
private AsyncRestTemplate asyncRestTemplate;

public ListenableFuture<ResponseEntity<MyCustomResponse>> exampleAsyncApiCall() {

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        HttpEntity request = new HttpEntity<MyCustomRequest>(headers);

        ListenableFuture<ResponseEntity<MyCustomResponse>> responseFuture
                = asyncRestTemplate.postForEntity("https://myurl.example.app/api/", request, MyCustomResponse.class);

        responseFuture.addCallback(new ListenableFutureCallback<ResponseEntity<MyCustomResponse>>() {

            @Override
            public void onSuccess(ResponseEntity<MyCustomResponse> myCustomResponseResponseEntity) {
                // TODO: Do something
            }
            @Override
            public void onFailure(Throwable throwable) { }
        });
        return responseFuture;
}

WebClient ExchangeFilterFunction Example

Note how I swapped the future callback with an ExchangeFilterFunction so that we could tap into the requests as they return. The following operations perform reactively only handling Mono’s allowing all downstream processing to happen only once the network operations are completed.

    ExchangeFilterFunction customCallback() {
        return ExchangeFilterFunction.ofResponseProcessor(clientResponse ->
                Mono.defer(() -> {
                    // TODO: Do something
                    return Mono.just(clientResponse);
                })
        );
    }

    public Mono<MyCustomResponse> exampleAsyncApiCall() {
        return WebClient.builder() // Ideally this should be pre-defined somewhere else and not created every time
                .filters(exchangeFilterFunctions -> exchangeFilterFunctions.add(customCallback()))
                .build()
                .post()
                .uri("https://myurl.example.app/api/")
                .accept(MediaType.APPLICATION_JSON)
                .bodyValue(myCustomRequest)
                .retrieve().bodyToMono(MyCustomResponse.class);
    }