diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/client/RestClientAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/client/RestClientAutoConfiguration.java index af44b3ae12ac..f89fc31b6609 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/client/RestClientAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/client/RestClientAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2024 the original author or authors. + * Copyright 2012-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -79,11 +79,10 @@ RestClientBuilderConfigurer restClientBuilderConfigurer( ObjectProvider> clientHttpRequestFactoryBuilder, ObjectProvider clientHttpRequestFactorySettings, ObjectProvider customizerProvider) { - RestClientBuilderConfigurer configurer = new RestClientBuilderConfigurer(); - configurer.setRequestFactoryBuilder(clientHttpRequestFactoryBuilder.getIfAvailable()); - configurer.setRequestFactorySettings(clientHttpRequestFactorySettings.getIfAvailable()); - configurer.setRestClientCustomizers(customizerProvider.orderedStream().toList()); - return configurer; + return new RestClientBuilderConfigurer( + clientHttpRequestFactoryBuilder.getIfAvailable(ClientHttpRequestFactoryBuilder::detect), + clientHttpRequestFactorySettings.getIfAvailable(ClientHttpRequestFactorySettings::defaults), + customizerProvider.orderedStream().toList()); } @Bean diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/client/RestClientBuilderConfigurer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/client/RestClientBuilderConfigurer.java index 56e8b4781314..50bc72dde59e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/client/RestClientBuilderConfigurer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/client/RestClientBuilderConfigurer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2024 the original author or authors. + * Copyright 2012-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.springframework.boot.autoconfigure.web.client; +import java.util.Collections; import java.util.List; import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder; @@ -32,21 +33,21 @@ */ public class RestClientBuilderConfigurer { - private ClientHttpRequestFactoryBuilder requestFactoryBuilder; + private final ClientHttpRequestFactoryBuilder requestFactoryBuilder; - private ClientHttpRequestFactorySettings requestFactorySettings; + private final ClientHttpRequestFactorySettings requestFactorySettings; - private List customizers; + private final List customizers; - void setRequestFactoryBuilder(ClientHttpRequestFactoryBuilder requestFactoryBuilder) { - this.requestFactoryBuilder = requestFactoryBuilder; + public RestClientBuilderConfigurer() { + this(ClientHttpRequestFactoryBuilder.detect(), ClientHttpRequestFactorySettings.defaults(), + Collections.emptyList()); } - void setRequestFactorySettings(ClientHttpRequestFactorySettings requestFactorySettings) { + RestClientBuilderConfigurer(ClientHttpRequestFactoryBuilder requestFactoryBuilder, + ClientHttpRequestFactorySettings requestFactorySettings, List customizers) { + this.requestFactoryBuilder = requestFactoryBuilder; this.requestFactorySettings = requestFactorySettings; - } - - void setRestClientCustomizers(List customizers) { this.customizers = customizers; } @@ -57,18 +58,14 @@ void setRestClientCustomizers(List customizers) { * @return the configured builder */ public RestClient.Builder configure(RestClient.Builder builder) { - ClientHttpRequestFactoryBuilder requestFactoryBuilder = (this.requestFactoryBuilder != null) - ? this.requestFactoryBuilder : ClientHttpRequestFactoryBuilder.detect(); - builder.requestFactory(requestFactoryBuilder.build(this.requestFactorySettings)); + builder.requestFactory(this.requestFactoryBuilder.build(this.requestFactorySettings)); applyCustomizers(builder); return builder; } private void applyCustomizers(Builder builder) { - if (this.customizers != null) { - for (RestClientCustomizer customizer : this.customizers) { - customizer.customize(builder); - } + for (RestClientCustomizer customizer : this.customizers) { + customizer.customize(builder); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/client/RestClientAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/client/RestClientAutoConfigurationTests.java index b5bb408f5992..fae799d96a97 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/client/RestClientAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/client/RestClientAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2024 the original author or authors. + * Copyright 2012-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,9 @@ import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration; import org.springframework.boot.autoconfigure.http.client.HttpClientAutoConfiguration; +import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder; +import org.springframework.boot.http.client.ClientHttpRequestFactorySettings; +import org.springframework.boot.http.client.ClientHttpRequestFactorySettings.Redirects; import org.springframework.boot.ssl.SslBundles; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.web.client.RestClientCustomizer; @@ -171,6 +174,57 @@ void whenHasFactoryProperty() { }); } + @Test + void shouldSupplyRestClientBuilderConfigurerWithCustomSettings() { + ClientHttpRequestFactorySettings clientHttpRequestFactorySettings = ClientHttpRequestFactorySettings.defaults() + .withRedirects(Redirects.DONT_FOLLOW); + ClientHttpRequestFactoryBuilder clientHttpRequestFactoryBuilder = mock( + ClientHttpRequestFactoryBuilder.class); + RestClientCustomizer customizer1 = mock(RestClientCustomizer.class); + RestClientCustomizer customizer2 = mock(RestClientCustomizer.class); + HttpMessageConvertersRestClientCustomizer httpMessageConverterCustomizer = mock( + HttpMessageConvertersRestClientCustomizer.class); + this.contextRunner.withBean(ClientHttpRequestFactorySettings.class, () -> clientHttpRequestFactorySettings) + .withBean(ClientHttpRequestFactoryBuilder.class, () -> clientHttpRequestFactoryBuilder) + .withBean("customizer1", RestClientCustomizer.class, () -> customizer1) + .withBean("customizer2", RestClientCustomizer.class, () -> customizer2) + .withBean("httpMessageConverterCustomizer", HttpMessageConvertersRestClientCustomizer.class, + () -> httpMessageConverterCustomizer) + .run((context) -> { + assertThat(context).hasSingleBean(RestClientBuilderConfigurer.class) + .hasSingleBean(ClientHttpRequestFactorySettings.class) + .hasSingleBean(ClientHttpRequestFactoryBuilder.class); + RestClientBuilderConfigurer configurer = context.getBean(RestClientBuilderConfigurer.class); + assertThat(configurer).hasFieldOrPropertyWithValue("requestFactoryBuilder", + clientHttpRequestFactoryBuilder); + assertThat(configurer).hasFieldOrPropertyWithValue("requestFactorySettings", + clientHttpRequestFactorySettings); + assertThat(configurer).hasFieldOrPropertyWithValue("customizers", + List.of(customizer1, customizer2, httpMessageConverterCustomizer)); + }); + } + + @Test + void shouldSupplyRestClientBuilderConfigurerWithAutoConfiguredHttpSettings() { + RestClientCustomizer customizer1 = mock(RestClientCustomizer.class); + RestClientCustomizer customizer2 = mock(RestClientCustomizer.class); + this.contextRunner.withBean("customizer1", RestClientCustomizer.class, () -> customizer1) + .withBean("customizer2", RestClientCustomizer.class, () -> customizer2) + .run((context) -> { + assertThat(context).hasSingleBean(RestClientBuilderConfigurer.class) + .hasSingleBean(ClientHttpRequestFactorySettings.class) + .hasSingleBean(ClientHttpRequestFactoryBuilder.class) + .hasSingleBean(HttpMessageConvertersRestClientCustomizer.class); + RestClientBuilderConfigurer configurer = context.getBean(RestClientBuilderConfigurer.class); + assertThat(configurer).hasFieldOrPropertyWithValue("requestFactoryBuilder", + context.getBean(ClientHttpRequestFactoryBuilder.class)); + assertThat(configurer).hasFieldOrPropertyWithValue("requestFactorySettings", + context.getBean(ClientHttpRequestFactorySettings.class)); + assertThat(configurer).hasFieldOrPropertyWithValue("customizers", List.of(customizer1, customizer2, + context.getBean(HttpMessageConvertersRestClientCustomizer.class))); + }); + } + @Configuration(proxyBeanMethods = false) static class CodecConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/client/RestClientBuilderConfigurerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/client/RestClientBuilderConfigurerTests.java index c4c8395c2177..4154e5e62328 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/client/RestClientBuilderConfigurerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/client/RestClientBuilderConfigurerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,11 +19,19 @@ import java.util.List; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder; +import org.springframework.boot.http.client.ClientHttpRequestFactorySettings; +import org.springframework.boot.ssl.SslBundle; import org.springframework.boot.web.client.RestClientCustomizer; +import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.web.client.RestClient; -import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.then; import static org.mockito.Mockito.mock; @@ -32,23 +40,29 @@ * * @author Moritz Halbritter */ +@ExtendWith(MockitoExtension.class) class RestClientBuilderConfigurerTests { + @Mock + private ClientHttpRequestFactoryBuilder clientHttpRequestFactoryBuilder; + + @Mock + private ClientHttpRequestFactory clientHttpRequestFactory; + @Test - void shouldApplyCustomizers() { - RestClientBuilderConfigurer configurer = new RestClientBuilderConfigurer(); + void shouldConfigureRestClientBuilder() { + ClientHttpRequestFactorySettings settings = ClientHttpRequestFactorySettings.ofSslBundle(mock(SslBundle.class)); RestClientCustomizer customizer = mock(RestClientCustomizer.class); - configurer.setRestClientCustomizers(List.of(customizer)); + RestClientCustomizer customizer1 = mock(RestClientCustomizer.class); + RestClientBuilderConfigurer configurer = new RestClientBuilderConfigurer(this.clientHttpRequestFactoryBuilder, + settings, List.of(customizer, customizer1)); + given(this.clientHttpRequestFactoryBuilder.build(settings)).willReturn(this.clientHttpRequestFactory); + RestClient.Builder builder = RestClient.builder(); configurer.configure(builder); + assertThat(builder.build()).hasFieldOrPropertyWithValue("clientRequestFactory", this.clientHttpRequestFactory); then(customizer).should().customize(builder); - } - - @Test - void shouldSupportNullAsCustomizers() { - RestClientBuilderConfigurer configurer = new RestClientBuilderConfigurer(); - configurer.setRestClientCustomizers(null); - assertThatCode(() -> configurer.configure(RestClient.builder())).doesNotThrowAnyException(); + then(customizer1).should().customize(builder); } }