In Spring Boot 3.0.0, ZipkinConfigurations.RestTemplateSenderConfiguration create a RestTemplate by relying on RestTemplateBuilder. The contract indicates that providing a ZipkinRestTemplateBuilderCustomizer would allow for customization of the generated RestTemplate.

However, RestTemplateBuilder is immutable and each method returns a new instance (contrary to the WebClient version). As a consequence, customization is impossible.

Example failing test:

    @Test
    void should_apply_interceptors() {
        ClientHttpRequestInterceptor interceptor1 = mock(ClientHttpRequestInterceptor.class);
        ZipkinRestTemplateBuilderCustomizer customizer = builder -> builder.additionalInterceptors(interceptor1);
        RestTemplate restTemplate = restTemplateSender(new ZipkinProperties(), new TestObjectProvider<>(customizer));

        // empty list
        assertThat(restTemplate.getInterceptors()).singleElement().isEqualTo(interceptor1);
    }

    // copied from org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinConfigurations.RestTemplateSenderConfiguration#restTemplateSender
    RestTemplate restTemplateSender(ZipkinProperties properties,
        ObjectProvider<ZipkinRestTemplateBuilderCustomizer> customizers) {
        RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder()
            .setConnectTimeout(properties.getConnectTimeout()).setReadTimeout(properties.getReadTimeout());

        customizers.orderedStream().forEach((customizer) -> customizer.customize(restTemplateBuilder));

        return restTemplateBuilder.build();
    }

    @RequiredArgsConstructor
    static class TestObjectProvider<T> implements ObjectProvider<T> {
        private final T t;

        @Override
        public T getObject(Object... args) throws BeansException {
            return t;
        }

        @Override
        public T getIfAvailable() throws BeansException {
            return t;
        }

        @Override
        public T getIfUnique() throws BeansException {
            return t;
        }

        @Override
        public T getObject() throws BeansException {
            return t;
        }

        @Override
        public Stream<T> orderedStream() {
            return Stream.of(t);
        }
    }

I think that it is required to make ZipkinRestTemplateBuilderCustomizer return a RestTemplateBuilder to have a working solution, or mutate the RestTemplate instead of the RestTemplateBuilder.

Work-around:

  1. Define your own ZipkinRestTemplateSender (which requires duplicating a lot of classes since ZipkinRestTemplateSender is package private)
  2. Use the web client version, which should not have this problem.

Comment From: wilkinsona

I think we should change the signature of the customize method from void customize(RestTemplateBuilder restTemplateBuilder) to RestTemplateBuilder customize(RestTemplateBuilder restTemplateBuilder). While it is technically a breaking change, I think it's OK as the method's useless in its current form.

Comment From: wilkinsona

We discussed this today and decided to change customize to return RestTemplateBuilder.