Skip to content

Commit ae2c0b1

Browse files
committed
Customize RestTemplateBuilder
Allow customization of RestTemplateBuilder when created by RestTemplateAutoConfiguration.
1 parent f7ef344 commit ae2c0b1

File tree

3 files changed

+93
-2
lines changed

3 files changed

+93
-2
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/client/RestTemplateAutoConfiguration.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,14 @@
3333
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
3434
import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration.NotReactiveWebApplicationCondition;
3535
import org.springframework.boot.web.client.RestTemplateBuilder;
36+
import org.springframework.boot.web.client.RestTemplateBuilderCustomizer;
3637
import org.springframework.boot.web.client.RestTemplateCustomizer;
3738
import org.springframework.boot.web.client.RestTemplateRequestCustomizer;
3839
import org.springframework.context.annotation.Bean;
3940
import org.springframework.context.annotation.Conditional;
4041
import org.springframework.context.annotation.Configuration;
4142
import org.springframework.context.annotation.Lazy;
43+
import org.springframework.util.Assert;
4244
import org.springframework.web.client.RestTemplate;
4345

4446
/**
@@ -59,6 +61,7 @@ public class RestTemplateAutoConfiguration {
5961
@ConditionalOnMissingBean
6062
public RestTemplateBuilder restTemplateBuilder(ObjectProvider<HttpMessageConverters> messageConverters,
6163
ObjectProvider<RestTemplateCustomizer> restTemplateCustomizers,
64+
ObjectProvider<RestTemplateBuilderCustomizer> restTemplateBuilderCustomizer,
6265
ObjectProvider<RestTemplateRequestCustomizer<?>> restTemplateRequestCustomizers) {
6366
RestTemplateBuilder builder = new RestTemplateBuilder();
6467
HttpMessageConverters converters = messageConverters.getIfUnique();
@@ -67,6 +70,10 @@ public RestTemplateBuilder restTemplateBuilder(ObjectProvider<HttpMessageConvert
6770
}
6871
builder = addCustomizers(builder, restTemplateCustomizers, RestTemplateBuilder::customizers);
6972
builder = addCustomizers(builder, restTemplateRequestCustomizers, RestTemplateBuilder::requestCustomizers);
73+
for (RestTemplateBuilderCustomizer customizer : restTemplateBuilderCustomizer) {
74+
builder = customizer.customize(builder);
75+
Assert.notNull(builder, "RestTemplateBuilderCustomizer returned null builder");
76+
}
7077
return builder;
7178
}
7279

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/client/RestTemplateAutoConfigurationTests.java

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,17 @@
2020
import java.util.List;
2121

2222
import org.junit.jupiter.api.Test;
23+
import org.mockito.Mockito;
2324

25+
import org.springframework.beans.factory.BeanCreationException;
2426
import org.springframework.boot.autoconfigure.AutoConfigurations;
2527
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
2628
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
2729
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
2830
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
2931
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
3032
import org.springframework.boot.web.client.RestTemplateBuilder;
33+
import org.springframework.boot.web.client.RestTemplateBuilderCustomizer;
3134
import org.springframework.boot.web.client.RestTemplateCustomizer;
3235
import org.springframework.boot.web.client.RestTemplateRequestCustomizer;
3336
import org.springframework.context.annotation.Bean;
@@ -42,10 +45,12 @@
4245
import org.springframework.web.client.RestTemplate;
4346

4447
import static org.assertj.core.api.Assertions.assertThat;
48+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
4549
import static org.mockito.ArgumentMatchers.any;
50+
import static org.mockito.BDDMockito.doThrow;
4651
import static org.mockito.BDDMockito.given;
47-
import static org.mockito.Mockito.mock;
48-
import static org.mockito.Mockito.verify;
52+
import static org.mockito.BDDMockito.mock;
53+
import static org.mockito.BDDMockito.verify;
4954

5055
/**
5156
* Tests for {@link RestTemplateAutoConfiguration}
@@ -157,6 +162,25 @@ void whenReactiveWebApplicationRestTemplateBuilderIsNotConfigured() {
157162
.run((context) -> assertThat(context).doesNotHaveBean(RestTemplateBuilder.class));
158163
}
159164

165+
@Test
166+
void customizerShouldCustomizeBuilder() {
167+
this.contextRunner.withUserConfiguration(RestTemplateBuilderCustomizerConfig.class).run((context) ->
168+
assertThatThrownBy(() -> context.getBean(RestTemplateBuilder.class).build())
169+
.isInstanceOf(IllegalStateException.class).hasMessageContaining("customized builder")
170+
);
171+
}
172+
173+
@Test
174+
void customizerShouldReturnInstanceNotANull() {
175+
this.contextRunner.withUserConfiguration(RestTemplateBuilderCustomizerReturnsNullConfig.class).run((context) ->
176+
assertThatThrownBy(() -> context.getBean(RestTemplateBuilder.class).build())
177+
.isInstanceOf(BeanCreationException.class)
178+
.hasMessageContaining("Error creating bean with name 'restTemplateBuilder'")
179+
.hasRootCauseInstanceOf(IllegalArgumentException.class)
180+
.hasRootCauseMessage("RestTemplateBuilderCustomizer returned null builder")
181+
);
182+
}
183+
160184
@Configuration(proxyBeanMethods = false)
161185
static class RestTemplateConfig {
162186

@@ -232,4 +256,28 @@ static class CustomHttpMessageConverter extends StringHttpMessageConverter {
232256

233257
}
234258

259+
@Configuration(proxyBeanMethods = false)
260+
static class RestTemplateBuilderCustomizerConfig {
261+
262+
@Bean
263+
RestTemplateBuilderCustomizer restTemplateBuilderCustomizer() {
264+
return (oldBuilder) -> {
265+
final RestTemplateBuilder builder = Mockito.spy(oldBuilder);
266+
doThrow(new IllegalStateException("customized builder")).when(builder).build();
267+
return builder;
268+
};
269+
}
270+
271+
}
272+
273+
@Configuration(proxyBeanMethods = false)
274+
static class RestTemplateBuilderCustomizerReturnsNullConfig {
275+
276+
@Bean
277+
RestTemplateBuilderCustomizer restTemplateBuilderCustomizer() {
278+
return (oldBuilder) -> null;
279+
}
280+
281+
}
282+
235283
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2012-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.web.client;
18+
19+
/**
20+
* Callback interface that can be used to customize a {@link RestTemplateBuilder}.
21+
*
22+
* @author Ivo Smid
23+
* @see RestTemplateBuilder
24+
* @since 5.3.0
25+
*/
26+
@FunctionalInterface
27+
public interface RestTemplateBuilderCustomizer {
28+
29+
/**
30+
* Callback to customize a {@link RestTemplateBuilder} instance.
31+
* @param restTemplateBuilder the original builder to customize
32+
* @return customized builder instance
33+
*/
34+
RestTemplateBuilder customize(RestTemplateBuilder restTemplateBuilder);
35+
36+
}

0 commit comments

Comments
 (0)