Open williamsuane opened 11 months ago
I am having the same problem. The requestFactory(new JdkClientHttpRequestFactory()) method replaced the original MockClientHttpRequestFactory in the injected Mock RestClient.Builder.
Here is a simple solution: just declare a bean to override the auto-configured RestClient.Builder.
@Configuration
public class RestClientBuilderConfiguration {
@Bean
public RestClient.Builder restClientBuilder() {
return RestClient.builder()
.requestFactory(new JdkClientHttpRequestFactory());
}
}
Thanks for trying the new @RestClientTest
support for RestClient
. The MockRestServiceServer
mocking works by setting the request factory to a MockClientHttpRequestFactory
that keeps track of the request being made so that they can be verified later. Calling RestClient.Builder.requestFactory()
directly is overriding this and breaking the mocking.
You can work around this for now by using a RestClientCustomizer
instead of directly modifying the builder, something like this:
@Bean
public RestClient restClient(RestClient.Builder builder) {
return builder.build();
}
@Bean
public RestClientCustomizer restClientCustomizer() {
return (restClientBuilder) -> restClientBuilder
.requestFactory(new JdkClientHttpRequestFactory())
.baseUrl(baseUrl);
}
Thanks for trying the new
@RestClientTest
support forRestClient
. TheMockRestServiceServer
mocking works by setting the request factory to aMockClientHttpRequestFactory
that keeps track of the request being made so that they can be verified later. CallingRestClient.Builder.requestFactory()
directly is overriding this and breaking the mocking.You can work around this for now by using a
RestClientCustomizer
instead of directly modifying the builder, something like this:@Bean public RestClient restClient(RestClient.Builder builder) { return builder.build(); } @Bean public RestClientCustomizer restClientCustomizer() { return (restClientBuilder) -> restClientBuilder .requestFactory(new JdkClientHttpRequestFactory()) .baseUrl(baseUrl); }
Thank you, Scott. It works for me.
I would like to ask why not make JdkClientHttpRequestFactory the default request factory for autowired RestClient.Builder bean. In my case, the default SimpleClientHttpRequestFactory returns an empty response body.
I would like to ask why not make JdkClientHttpRequestFactory the default request factory for autowired RestClient.Builder
Thanks @Washingtonwei. I've created #38856 for us to take a look at the defaults for the Spring Boot auto-configuration.
This doesn't look like specific to RestClient
and there is an issue in Spring Framework under consideration to provide a hook point to avoid this problem: https://github.com/spring-projects/spring-framework/issues/32338
Hello,
I have a very similar problem but from the other angle.
I am trying to test timeouts and retries using MockRestServiceServer
but because it replaces the original factory with MockClientHttpRequestFactory
all the settings are lost.
Here's the example code:
@Configuration
class RestClientConfiguration {
@Bean
fun clientHttpRequestFactory(
@Value("\${restClient.connectionTimeout:30}") connectionTimeout: Int,
@Value("\${restClient.maxRetryAttempts:3}") maxRetryAttempts: Int,
@Value("\${restClient.retryDelayMilliseconds:300}") retryDelayMilliseconds: Long
): ClientHttpRequestFactory {
val retryDelay = TimeValue.ofMilliseconds(retryDelayMilliseconds)
val client =
HttpClients.custom().setRetryStrategy(DefaultHttpRequestRetryStrategy(maxRetryAttempts, retryDelay)).build()
return HttpComponentsClientHttpRequestFactory(client).apply { setConnectTimeout(connectionTimeout) }
}
@Bean
fun restClientBuilder(clientHttpRequestFactory: ClientHttpRequestFactory): RestClient.Builder =
RestClient.builder().requestFactory(clientHttpRequestFactory).baseUrl("http://www.google.com")
}
And here is the setup of the MockRestServiceServer
@RunWith(SpringRunner::class)
@RestClientTest(ServiceRestClient::class)
@Import(RestClientConfiguration::class)
class ServiceRestClientTest
@Autowired
private lateinit var builder: RestClient.Builder
private lateinit var client: ServiceRestClient
private lateinit var server: MockRestServiceServer
@Autowired lateinit var objectMapper: ObjectMapper
@BeforeEach
fun before() {
val mockServer = MockRestServiceServer.bindTo(builder).build()
server = mockServer
client = ServiceRestClient(builder, objectMapper)
}
...
Is there a way I can test the delays and retries using this setup?
Thanks for trying the new
@RestClientTest
support forRestClient
. TheMockRestServiceServer
mocking works by setting the request factory to aMockClientHttpRequestFactory
that keeps track of the request being made so that they can be verified later. CallingRestClient.Builder.requestFactory()
directly is overriding this and breaking the mocking.You can work around this for now by using a
RestClientCustomizer
instead of directly modifying the builder, something like this:@Bean public RestClient restClient(RestClient.Builder builder) { return builder.build(); } @Bean public RestClientCustomizer restClientCustomizer() { return (restClientBuilder) -> restClientBuilder .requestFactory(new JdkClientHttpRequestFactory()) .baseUrl(baseUrl); }
I have not changed any default implementations, I have two API's, one for the same JSON placeholder, and another contacting another Spring Boot server running locally. I got the Json placeholder to work, but locally, I am getting the same error without any customisation
Description
When creating RestClient Bean with JdkClientHttpRequestFactory, like below
Tests using
@RestClientTest
andMockRestServiceServer
fail to connect.Sample Application
https://github.com/williamsuane/failing-cat-fact/tree/master
Just execute the following test, as is
it blows with the following exception
By removing the
.requestFactory(new JdkClientHttpRequestFactory())
fromThe test works perfectly.