Affects: \


The new HTTP interface clients only supports WebClient, for MVC users this means an additional dependency on web-flux and dealing with Spring boot auto configuration for web-flux.

Comment From: rstoyanchev

hi @ooraini, thanks for bringing this up.

HttpClientAdapter can be implemented quite easily with the RestTemplate. For example:

RestTemplateAdapter

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.util.Assert;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.service.invoker.HttpClientAdapter;
import org.springframework.web.service.invoker.HttpRequestValues;


public class RestTemplateAdapter implements HttpClientAdapter {

    private final RestTemplate restTemplate;


    public RestTemplateAdapter(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }


    @Override
    public Mono<Void> requestToVoid(HttpRequestValues values) {
        this.restTemplate.exchange(newRequest(values), Void.class);
        return Mono.empty();
    }

    @Override
    public Mono<HttpHeaders> requestToHeaders(HttpRequestValues values) {
        HttpHeaders headers = this.restTemplate.exchange(newRequest(values), Void.class).getHeaders();
        return Mono.just(headers);
    }

    @Override
    public <T> Mono<T> requestToBody(HttpRequestValues values, ParameterizedTypeReference<T> type) {
        T body = this.restTemplate.exchange(newRequest(values), type).getBody();
        return Mono.justOrEmpty(body);
    }

    @Override
    public <T> Flux<T> requestToBodyFlux(HttpRequestValues values, ParameterizedTypeReference<T> type) {
        throw new UnsupportedOperationException("Not supported with RestTemplate");
    }

    @Override
    public Mono<ResponseEntity<Void>> requestToBodilessEntity(HttpRequestValues values) {
        ResponseEntity<Void> entity = this.restTemplate.exchange(newRequest(values), Void.class);
        return Mono.just(entity);
    }

    @Override
    public <T> Mono<ResponseEntity<T>> requestToEntity(HttpRequestValues values, ParameterizedTypeReference<T> type) {
        ResponseEntity<T> entity = this.restTemplate.exchange(newRequest(values), type);
        return Mono.just(entity);
    }

    @Override
    public <T> Mono<ResponseEntity<Flux<T>>> requestToEntityFlux(HttpRequestValues values, ParameterizedTypeReference<T> type) {
        throw new UnsupportedOperationException("Not supported with RestTemplate");
    }

    @SuppressWarnings("ReactiveStreamsUnusedPublisher")
    private RequestEntity<?> newRequest(HttpRequestValues values) {

        HttpMethod httpMethod = values.getHttpMethod();
        Assert.notNull(httpMethod, "HttpMethod is required");

        RequestEntity.BodyBuilder builder;

        if (values.getUri() != null) {
            builder = RequestEntity.method(httpMethod, values.getUri());
        }
        else if (values.getUriTemplate() != null) {
            builder = RequestEntity.method(httpMethod, values.getUriTemplate(), values.getUriVariables());
        }
        else {
            throw new IllegalStateException("Neither full URL nor URI template");
        }

        builder.headers(headers -> headers.putAll(values.getHeaders()));
        // TODO: cookies

        if (values.getBodyValue() != null) {
            builder.body(values.getBodyValue());
        }
        else if (values.getBody() != null) {
            throw new IllegalArgumentException("Publisher body is not supported");
        }

        return builder.build();
    }

}

Mainly, it's the Flux methods that are excluded as those cannot be supported with the RestTemplate, and likewise, it's not an option to use Flux or Mono as inputs in @HttpExchange methods either. Aside from that, the rest should work.

There are a couple of things we can consider as part of this request:

  1. Providing an implementation like the one above.
  2. Supporting an alternative HttpClientAdapter contract that does not depend on Reactor.

The work for #29552 should also help to inform decisions we make here. In particular of interest is whether a Loom-friendly contract would support asynchronous requests, and streaming with decoding to objects.

Comment From: OlgaMaciaszek

We are going to experiment with this for 6.1.