Affects: spring 6.1.0-RC2 with spring boot 3.2.0-RC2 and JDK21
Description
I've attached a sample Spring Boot application with a single endpoint that accepts PATCH requests. When the endpoint is invoked with a PATCH request from a WebTestClient it is allowed, but when it is invoked with a PATCH request from a RestClient, it fails with the following exception
org.springframework.web.client.ResourceAccessException: I/O error on PATCH request for "http://localhost:61668/api/endpoint": Invalid HTTP method: PATCH
at org.springframework.web.client.DefaultRestClient$DefaultRequestBodyUriSpec.createResourceAccessException(DefaultRestClient.java:489)
at org.springframework.web.client.DefaultRestClient$DefaultRequestBodyUriSpec.exchangeInternal(DefaultRestClient.java:414)
at org.springframework.web.client.DefaultRestClient$DefaultRequestBodyUriSpec.retrieve(DefaultRestClient.java:380)
In SecurityConfiguration.java I've added PATCH to the allowed methods, so I guess RestClient is ignoring this configuration.
Steps to Reproduce demo.zip
The application contains 2 integration tests, one of which invokes the endpoint with a RestClient and the other uses WebTestClient. The latter test passes, but the former fails.
Comment From: poutsma
Spring Boot's RestClient support uses the SimpleClientHttpRequestFactory by default, which is based on the dated java.net.HttpURLConnection, and does not have support for PATCH.
Switching to the more modern Java HttpClient fixes it:
@PostConstruct
private void buildRestClient() {
restClient = restClientBuilder.baseUrl("http://localhost:" + port)
.requestFactory(new JdkClientHttpRequestFactory())
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
}
Comment From: andrei-ivanov
Wouldn't it make sense to change the default client?
Comment From: donalmurtagh
Spring Boot's
RestClientsupport uses theSimpleClientHttpRequestFactoryby default, which is based on the datedjava.net.HttpURLConnection, and does not have support forPATCH.Switching to the more modern Java HttpClient fixes it:
@poutsma Thanks very much for your reply, I've confirmed that switching the request factory resolves the problem.
Given that RestClient is brand new, shouldn't it use JdkClientHttpRequestFactory by default i.e. there doesn't appear to be a backwards compatibility argument for using HttpURLConnection
Comment From: poutsma
Wouldn't it make sense to change the default client?
FWIW, RestClient's default request factory—without Boot—is the JdkClientHttpRequestFactory.
It is because Boot uses the same ClientHttpRequestFactorySettings between RestTemplate and RestClient that the SimpleClientHttpRequestFactory is used, doing otherwise would break backward compatibility for RestTemplate users because the factories have different behavior with regards to redirects.
There are plans to improve the situation, see https://github.com/spring-projects/spring-boot/issues/36266