When using RestTemplateBuilder in a native-image, for example in this code:
private final RestTemplateBuilder restTemplateBuilder;
// ...
RestTemplate restTemplate = this.restTemplateBuilder
.setConnectTimeout(Duration.ofSeconds(5))
.setReadTimeout(Duration.ofSeconds(5))
.build();
then this fails in a native image with this stacktrace:
java.lang.IllegalStateException: Request factory class org.springframework.http.client.SimpleClientHttpRequestFactory does not have a suitable setConnectTimeout method
at org.springframework.boot.web.client.RestTemplateBuilder$RequestFactoryCustomizer.findMethod(RestTemplateBuilder.java:782)
at org.springframework.boot.web.client.RestTemplateBuilder$RequestFactoryCustomizer.setConnectTimeout(RestTemplateBuilder.java:761)
at org.springframework.boot.web.client.RestTemplateBuilder$RequestFactoryCustomizer.accept(RestTemplateBuilder.java:736)
at org.springframework.boot.web.client.RestTemplateBuilder.buildRequestFactory(RestTemplateBuilder.java:656)
at org.springframework.boot.web.client.RestTemplateBuilder.configure(RestTemplateBuilder.java:614)
at org.springframework.boot.web.client.RestTemplateBuilder.build(RestTemplateBuilder.java:589)
at com.example.resttemplate.CLR.http(CLR.java:33)
at com.example.resttemplate.CLR.run(CLR.java:26)
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:768)
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:752)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at com.example.resttemplate.RestTemplateApplication.main(RestTemplateApplication.java:13)
This can be observed in https://ci.spring.io/teams/spring-aot-smoke-tests/pipelines/spring-aot-smoke-tests-1.0.x/jobs/rest-template/builds/1
Comment From: mhalbritter
The interface org.springframework.http.client.ClientHttpRequestFactory in Spring Framework doesn't have the methods
setConnectTimeoutsetReadTimeoutsetBufferRequestBody
which the RestTemplateBuilder needs to set. Some of the implementing classes have these methods, for example:
org.springframework.http.client.HttpComponentsClientHttpRequestFactoryorg.springframework.http.client.OkHttp3ClientHttpRequestFactory- this one doesn't havesetBufferRequestBodyorg.springframework.http.client.SimpleClientHttpRequestFactoryorg.springframework.http.client.Netty4ClientHttpRequestFactory- this one doesn't havesetBufferRequestBody
I wonder if we should introduce a new interface in Spring Framework for configurable ClientHttpRequestFactorys, which would remove this reflection call.
If this isn't possible, we have to include the methods on the implementing classes in the reflection metadata.
Comment From: mhalbritter
We could add an interface in Boot with multiple implementations for every HttpRequestFactory type to get rid of the reflective call, too.
Comment From: mhalbritter
I decided to not refactor the reflection away and went for the RuntimeHints way instead. I made ClientHttpRequestFactorySupplier more native-friendly by introducting _PRESENT constants.
Comment From: akefirad
@mhalbritter does it make sense to refactor the following to add hints only if the method exists:
private void registerReflectionHints(ReflectionHints hints,
Class<? extends ClientHttpRequestFactory> requestFactoryType, Consumer<TypeHint.Builder> hintCustomizer) {
hints.registerType(requestFactoryType, (typeHint) -> {
typeHint.withMethod("setConnectTimeout", TypeReference.listOf(int.class), ExecutableMode.INVOKE);
typeHint.withMethod("setReadTimeout", TypeReference.listOf(int.class), ExecutableMode.INVOKE);
typeHint.withMethod("setBufferRequestBody", TypeReference.listOf(boolean.class), ExecutableMode.INVOKE);
hintCustomizer.accept(typeHint);
});
}
Since it generates warning while building the native image if for example setBufferRequestBody for OkHttp3ClientHttpRequestFactory:
Warning: Method org.springframework.http.client.OkHttp3ClientHttpRequestFactory.setBufferRequestBody(boolean) not found.
If not, Is there any workaround on the application side to fix/clean-up the hint so that we don't see the warning?
Comment From: snicoll
Good catch @akefirad, I've created #33203