If i create a declarative HTTP client with HttpServiceProxyFactory
it fails when I try to turn the application with spring boot 3 snapshots into a graalvm native image. I've been able to make declarative HTTP clients with some tweaks to my app:
@RegisterReflectionForBinding
for the DTO my HTTP client interface deals with (e.g.Customer
)- register a JDK proxy in a
RuntimeHintsRegistrar
for the JDK proxy that results:hints.proxies().registerJdkProxy(CrmClient.class, SpringProxy.class, Advised.class, DecoratingProxy.class )
it would be nice to have the framework automatically contribute the hints for me, discovering all the input parameters and return values of my interfaces and supporting them, and registering the types for the proxy that's ultimately created.
Comment From: joshlong
btw the full code example is https://github.com/joshlong/cloud-native-java-2022/blob/main/e2e5/edge2/src/main/java/com/example/edge2/Edge2Application.java
package com.example.edge2;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.annotation.RegisterReflectionForBinding;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.core.DecoratingProxy;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.support.WebClientAdapter;
import org.springframework.web.service.annotation.GetExchange;
import org.springframework.web.service.invoker.HttpServiceProxyFactory;
import reactor.core.publisher.Flux;
@SpringBootApplication
@RegisterReflectionForBinding(Customer.class)
@ImportRuntimeHints(Edge2Application.Hints.class)
public class Edge2Application {
static class Hints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints
.proxies()
.registerJdkProxy(
com.example.edge2.CrmClient.class, org.springframework.aop.SpringProxy.class,
org.springframework.aop.framework.Advised.class, DecoratingProxy.class
);
}
}
public static void main(String[] args) {
SpringApplication.run(Edge2Application.class, args);
}
@Bean
ApplicationListener<ApplicationReadyEvent> httpClientRunner(CrmClient crmClient) {
return event -> crmClient.getCustomers().subscribe(System.out::println);
}
@Bean
HttpServiceProxyFactory httpServiceProxyFactory(WebClient.Builder http) {
return WebClientAdapter.createHttpServiceProxyFactory(http.baseUrl("http://localhost:8080/"));
}
@Bean
CrmClient crmClient(HttpServiceProxyFactory httpServiceProxyFactory) {
return httpServiceProxyFactory.createClient(CrmClient.class);
}
}
interface CrmClient {
@GetExchange(url = "/customers")
Flux<Customer> getCustomers();
}
record Customer(Integer id, String name) {
}