diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTestContextCustomizer.java b/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTestContextCustomizer.java index 166e1d5b44..623804aab8 100644 --- a/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTestContextCustomizer.java +++ b/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTestContextCustomizer.java @@ -16,11 +16,19 @@ package org.springframework.boot.test.context; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.boot.test.web.client.LocalHostUriTemplateHandler; import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.annotation.AnnotatedElementUtils; -import org.springframework.core.env.Environment; import org.springframework.test.context.ContextCustomizer; import org.springframework.test.context.MergedContextConfiguration; @@ -38,12 +46,24 @@ class SpringBootTestContextCustomizer implements ContextCustomizer { SpringBootTest annotation = AnnotatedElementUtils.getMergedAnnotation( mergedContextConfiguration.getTestClass(), SpringBootTest.class); if (annotation.webEnvironment().isEmbedded()) { - Object restTemplate = TestRestTemplateFactory - .createRestTemplate(context.getEnvironment()); - context.getBeanFactory().registerSingleton("testRestTemplate", restTemplate); + registerTestRestTemplate(context); } } + private void registerTestRestTemplate(ConfigurableApplicationContext context) { + ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); + if (beanFactory instanceof BeanDefinitionRegistry) { + registerTestRestTemplate(context, (BeanDefinitionRegistry) context); + } + + } + + private void registerTestRestTemplate(ConfigurableApplicationContext context, + BeanDefinitionRegistry registry) { + registry.registerBeanDefinition("testRestTemplate", + new RootBeanDefinition(TestRestTemplateFactory.class)); + } + @Override public int hashCode() { return getClass().hashCode(); @@ -57,13 +77,47 @@ class SpringBootTestContextCustomizer implements ContextCustomizer { return true; } - // Inner class to avoid references to web classes that may not be on the classpath - private static class TestRestTemplateFactory { + /** + * {@link FactoryBean} used to create a configure a {@link TestRestTemplate}. + */ + public static class TestRestTemplateFactory + implements FactoryBean, ApplicationContextAware { - private static TestRestTemplate createRestTemplate(Environment environment) { - TestRestTemplate template = new TestRestTemplate(); - template.setUriTemplateHandler(new LocalHostUriTemplateHandler(environment)); - return template; + private TestRestTemplate object; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException { + RestTemplateBuilder builder = getRestTemplateBuilder(applicationContext); + TestRestTemplate template = new TestRestTemplate(builder.build()); + template.setUriTemplateHandler( + new LocalHostUriTemplateHandler(applicationContext.getEnvironment())); + this.object = template; + } + + private RestTemplateBuilder getRestTemplateBuilder( + ApplicationContext applicationContext) { + try { + return applicationContext.getBean(RestTemplateBuilder.class); + } + catch (NoSuchBeanDefinitionException ex) { + return new RestTemplateBuilder(); + } + } + + @Override + public boolean isSingleton() { + return true; + } + + @Override + public Class getObjectType() { + return TestRestTemplate.class; + } + + @Override + public TestRestTemplate getObject() throws Exception { + return this.object; } } diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java b/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java index 08990f8665..a4982dafac 100644 --- a/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java +++ b/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java @@ -91,30 +91,22 @@ public class TestRestTemplate { */ public TestRestTemplate(String username, String password, HttpClientOption... httpClientOptions) { - this.restTemplate = createRestTemplate(username, password, httpClientOptions); + this(new RestTemplate(), username, password, httpClientOptions); } - /** - * Factory method used to create the underlying {@link RestTemplate}. - * @param username the username to use (or {@code null}) - * @param password the password (or {@code null}) - * @param httpClientOptions client options to use if the Apache HTTP Client is used - * @return the delegate {@link RestTemplate} - */ - protected RestTemplate createRestTemplate(String username, String password, + public TestRestTemplate(RestTemplate restTemplate) { + this(restTemplate, null, null); + } + + public TestRestTemplate(RestTemplate restTemplate, String username, String password, HttpClientOption... httpClientOptions) { - RestTemplate restTemplate = new RestTemplate(); + Assert.notNull(restTemplate, "RestTemplate must not be null"); if (ClassUtils.isPresent("org.apache.http.client.config.RequestConfig", null)) { restTemplate.setRequestFactory( new CustomHttpComponentsClientHttpRequestFactory(httpClientOptions)); } addAuthentication(restTemplate, username, password); restTemplate.setErrorHandler(new NoOpResponseErrorHandler()); - return restTemplate; - } - - public TestRestTemplate(RestTemplate restTemplate) { - Assert.notNull(restTemplate, "RestTemplate must not be null"); this.restTemplate = restTemplate; } diff --git a/spring-boot-test/src/test/java/org/springframework/boot/test/context/AbstractSpringBootTestEmbeddedWebEnvironmentTests.java b/spring-boot-test/src/test/java/org/springframework/boot/test/context/AbstractSpringBootTestEmbeddedWebEnvironmentTests.java index cb02aae86b..7617948e64 100644 --- a/spring-boot-test/src/test/java/org/springframework/boot/test/context/AbstractSpringBootTestEmbeddedWebEnvironmentTests.java +++ b/spring-boot-test/src/test/java/org/springframework/boot/test/context/AbstractSpringBootTestEmbeddedWebEnvironmentTests.java @@ -60,6 +60,10 @@ public abstract class AbstractSpringBootTestEmbeddedWebEnvironmentTests { @Autowired private TestRestTemplate restTemplate; + public TestRestTemplate getRestTemplate() { + return this.restTemplate; + } + @Test public void runAndTestHttpEndpoint() { assertThat(this.port).isNotEqualTo(8080).isNotEqualTo(0); diff --git a/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestWebEnvironmentRandomPortTests.java b/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestWebEnvironmentRandomPortTests.java index f2efd286d4..516f33fc3f 100644 --- a/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestWebEnvironmentRandomPortTests.java +++ b/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestWebEnvironmentRandomPortTests.java @@ -16,15 +16,21 @@ package org.springframework.boot.test.context; +import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import static org.assertj.core.api.Assertions.assertThat; + /** * Tests for {@link SpringBootTest} configured with {@link WebEnvironment#RANDOM_PORT}. * @@ -37,11 +43,28 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc; public class SpringBootTestWebEnvironmentRandomPortTests extends AbstractSpringBootTestEmbeddedWebEnvironmentTests { + @Test + public void testRestTemplateShouldUseBuilder() throws Exception { + assertThat(getRestTemplate().getRestTemplate().getMessageConverters()) + .hasAtLeastOneElementOfType(MyConverter.class); + } + @Configuration @EnableWebMvc @RestController protected static class Config extends AbstractConfig { + @Bean + public RestTemplateBuilder restTemplateBuilder() { + return new RestTemplateBuilder() + .additionalMessageConverters(new MyConverter()); + + } + + } + + private static class MyConverter extends StringHttpMessageConverter { + } }