0

I'm trying to build web app based on Spring Boot 3 and planning to run this in Kubernetes as native images. So my goal is to build native image, but it is where I got issue with Feign here.

My app is using Feign client to access third party API.

Application works perfect when run as plain Java application in non-native mode. But once I'm running it as native image in Docker, it is unable to make third party calls because request/response DTO types are not available in native runtime, forcing Jackson to throw error:

Cannot construct instance of `com.steam.trading.trade.bot.client.steam.dto.SteamResponse`: cannot deserialize from Object value (no delegate- or property-based Creator): this appears to be a native image, in which case you may need to configure reflection for the class that is to be deserialized

What I understand from this error is that AOT serialization hints are not created for Feign Client request/response dto data types. Also listing all classes for serialization is not an options, since it will be a lot of manual work to do and easy to miss something there.

Question is, is this some kind of bug in Open Feign, is there out of box RuntimeHintsRegistrar to import or should I register all DTO's by myself?

Project setup

I'm using Spring Boot 3 and OpenFeign from Spring Cloud dependencies. Versions are:

    <spring-boot.version>3.0.4</spring-boot.version>
    <spring-cloud.version>2022.0.1</spring-cloud.version>

I have following Feign client:

@FeignClient(name = "steam-server-time-api", url = "${app.steam.api}", configuration = FeignSteamConfiguration.class)
public interface ServerTimeClient {

    @RequestLine("POST /ITwoFactorService/QueryTime/v1/")
    SteamResponse<QueryTime> getServerTime();
}

And following Feign Configuration:

public class FeignSteamConfiguration {

    @Bean
    public Contract useFeignAnnotations() {
        return new Contract.Default();
    }

    @Bean
    public Encoder feignFormEncoder(ObjectFactory<HttpMessageConverters> messageConverters) {
        return new FormEncoder(new SpringEncoder(messageConverters));
    }

    @Bean
    public ErrorDecoder clientErrorDecoder() {
        return new CustomErrorDecoder();
    }
}

I tried Both default and Spring Contracts, but issue is the same.

I'm building images using command:

mvn -Pnative spring-boot:build-image

I tried to register manually, using RegisterReflectionForBinding, but having 50+ classes is not really good to manually list all of them. Also I tried to switch Default and Spring contracts, but it issue is still the same.

1 Answers1

0

Some libraries (like Jackson) that do serialization/deserialization of objects don't know how to do this in the spring native's runtime, so you should tell/register to spring native about the proxies classes, resource files/paths, reflected methods, or objects to serialize/deserialize.

So I believe that you'll need to create a class implementing the RuntimeHintsRegistrar interface and set up what are the classes that you'll need to serialize/deserialize, as described in this link: https://docs.spring.io/spring-boot/docs/current/reference/html/native-image.html#native-image.advanced.custom-hints (spring native custom hints)

or annotate in some config class this below annotation: @RegisterReflectionForBinding({YourCustomObject.class})