diff --git a/autoconfigure/src/main/java/io/freefair/spring/okhttp/OkHttp3AutoConfiguration.java b/autoconfigure/src/main/java/io/freefair/spring/okhttp/OkHttp3AutoConfiguration.java index a91eddc..108006f 100644 --- a/autoconfigure/src/main/java/io/freefair/spring/okhttp/OkHttp3AutoConfiguration.java +++ b/autoconfigure/src/main/java/io/freefair/spring/okhttp/OkHttp3AutoConfiguration.java @@ -3,15 +3,12 @@ import okhttp3.*; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.http.client.OkHttp3ClientHttpRequestFactory; import java.io.File; import java.io.IOException; @@ -95,20 +92,4 @@ public Cache okHttp3Cache() throws IOException { } return new Cache(directory, okHttpProperties.getCache().getMaxSize().toBytes()); } - - /** - * @author Lars Grefer - */ - @Configuration(proxyBeanMethods = false) - @ConditionalOnClass(OkHttp3ClientHttpRequestFactory.class) - @AutoConfigureBefore(OkHttpRestTemplateAutoConfiguration.class) - @AutoConfigureAfter(OkHttp3AutoConfiguration.class) - public static class RequestFactoryAutoConfiguration { - - @Bean - @ConditionalOnMissingBean(OkHttp3ClientHttpRequestFactory.class) - public OkHttp3ClientHttpRequestFactory okHttp3ClientHttpRequestFactory(OkHttpClient okHttpClient) { - return new OkHttp3ClientHttpRequestFactory(okHttpClient); - } - } } diff --git a/autoconfigure/src/main/java/io/freefair/spring/okhttp/OkHttpRestTemplateAutoConfiguration.java b/autoconfigure/src/main/java/io/freefair/spring/okhttp/OkHttpRestTemplateAutoConfiguration.java index 210c0a2..fd4651e 100644 --- a/autoconfigure/src/main/java/io/freefair/spring/okhttp/OkHttpRestTemplateAutoConfiguration.java +++ b/autoconfigure/src/main/java/io/freefair/spring/okhttp/OkHttpRestTemplateAutoConfiguration.java @@ -1,29 +1,80 @@ package io.freefair.spring.okhttp; +import okhttp3.OkHttpClient; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.boot.autoconfigure.condition.NoneNestedConditions; +import org.springframework.boot.autoconfigure.http.HttpMessageConverters; +import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration; import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration; +import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.boot.web.client.RestTemplateCustomizer; +import org.springframework.boot.web.client.RestTemplateRequestCustomizer; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.Order; import org.springframework.http.client.OkHttp3ClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; +import java.util.Collection; +import java.util.List; +import java.util.function.BiFunction; +import java.util.stream.Collectors; + /** * @author Lars Grefer + * @see RestTemplateAutoConfiguration */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass({RestTemplateCustomizer.class, RestTemplate.class}) @AutoConfigureBefore(RestTemplateAutoConfiguration.class) +@AutoConfigureAfter(HttpMessageConvertersAutoConfiguration.class) +@Conditional(OkHttpRestTemplateAutoConfiguration.NotReactiveWebApplicationCondition.class) public class OkHttpRestTemplateAutoConfiguration { @Bean - @Order(2) - @ConditionalOnBean(OkHttp3ClientHttpRequestFactory.class) - public RestTemplateCustomizer okHttp3RestTemplateCustomizer(OkHttp3ClientHttpRequestFactory requestFactory) { - return restTemplate -> restTemplate.setRequestFactory(requestFactory); + @ConditionalOnMissingBean + public RestTemplateBuilder restTemplateBuilder(ObjectProvider messageConverters, + ObjectProvider restTemplateCustomizers, + ObjectProvider> restTemplateRequestCustomizers, + OkHttpClient okHttpClient) { + RestTemplateBuilder builder = new RestTemplateBuilder(); + HttpMessageConverters converters = messageConverters.getIfUnique(); + if (converters != null) { + builder = builder.messageConverters(converters.getConverters()); + } + builder = addCustomizers(builder, restTemplateCustomizers, RestTemplateBuilder::customizers); + builder = addCustomizers(builder, restTemplateRequestCustomizers, RestTemplateBuilder::requestCustomizers); + + builder = builder.requestFactory(() -> new OkHttp3ClientHttpRequestFactory(okHttpClient)); + + return builder; + } + + private RestTemplateBuilder addCustomizers(RestTemplateBuilder builder, ObjectProvider objectProvider, + BiFunction, RestTemplateBuilder> method) { + List customizers = objectProvider.orderedStream().collect(Collectors.toList()); + if (!customizers.isEmpty()) { + return method.apply(builder, customizers); + } + return builder; + } + + static class NotReactiveWebApplicationCondition extends NoneNestedConditions { + + NotReactiveWebApplicationCondition() { + super(ConfigurationPhase.PARSE_CONFIGURATION); + } + + @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) + private static class ReactiveWebApplication { + + } + } } diff --git a/autoconfigure/src/test/java/io/freefair/spring/okhttp/OkHttpRestTemplateAutoConfigurationTest.java b/autoconfigure/src/test/java/io/freefair/spring/okhttp/OkHttpRestTemplateAutoConfigurationTest.java new file mode 100644 index 0000000..d042e14 --- /dev/null +++ b/autoconfigure/src/test/java/io/freefair/spring/okhttp/OkHttpRestTemplateAutoConfigurationTest.java @@ -0,0 +1,63 @@ +package io.freefair.spring.okhttp; + +import okhttp3.OkHttpClient; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.http.client.AbstractClientHttpRequestFactoryWrapper; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.OkHttp3ClientHttpRequestFactory; +import org.springframework.web.client.RestTemplate; + +import java.lang.reflect.Field; +import java.time.Duration; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, + properties = { + "okhttp.read-timeout=21s", + "okhttp.connect-timeout=21s", + "okhttp.write-timeout=21s" + }) +class OkHttpRestTemplateAutoConfigurationTest { + + @Autowired + private RestTemplateBuilder restTemplateBuilder; + + @Test + void testTimeouts() throws NoSuchFieldException, IllegalAccessException { + RestTemplate restTemplate = restTemplateBuilder.setConnectTimeout(Duration.ofSeconds(42)).build(); + + OkHttpClient client = extractClient(restTemplate); + + assertThat(client.connectTimeoutMillis()).isEqualTo(Duration.ofSeconds(42).toMillis()); + assertThat(client.readTimeoutMillis()).isEqualTo(Duration.ofSeconds(21).toMillis()); + assertThat(client.writeTimeoutMillis()).isEqualTo(Duration.ofSeconds(21).toMillis()); + } + + private OkHttpClient extractClient(RestTemplate restTemplate) throws NoSuchFieldException, IllegalAccessException { + ClientHttpRequestFactory requestFactory = restTemplate.getRequestFactory(); + + while (requestFactory instanceof AbstractClientHttpRequestFactoryWrapper) { + Field field = AbstractClientHttpRequestFactoryWrapper.class.getDeclaredField("requestFactory"); + field.setAccessible(true); + requestFactory = (ClientHttpRequestFactory) field.get(requestFactory); + } + + assertThat(requestFactory).isInstanceOf(OkHttp3ClientHttpRequestFactory.class); + + Field field = OkHttp3ClientHttpRequestFactory.class.getDeclaredField("client"); + field.setAccessible(true); + return (OkHttpClient) field.get(requestFactory); + } + + @SpringBootConfiguration + @EnableAutoConfiguration + public static class TestConfiguration { + + } +} diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 8ecd519..732ec20 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -39,7 +39,6 @@ -