Hello,

Bug description From 1.0.0-M6, compiling a native image, using OpenAI, fails at runtime with

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.lang.IllegalArgumentException: No @JsonProperty fields found in the org.springframework.ai.openai.OpenAiChatOptions] with root cause

java.lang.IllegalArgumentException: No @JsonProperty fields found in the org.springframework.ai.openai.OpenAiChatOptions
    at org.springframework.ai.model.ModelOptionsUtils.merge(ModelOptionsUtils.java:167)
    at org.springframework.ai.model.ModelOptionsUtils.merge(ModelOptionsUtils.java:199)
    at org.springframework.ai.openai.OpenAiChatModel.buildRequestPrompt(OpenAiChatModel.java:579)
[...]

Looks like this check introduced make the thing less plug and play https://github.com/spring-projects/spring-ai/blob/bed1db352a44da91d4a3f1bf2383cbaf5e361247/spring-ai-core/src/main/java/org/springframework/ai/model/ModelOptionsUtils.java#L166-L168

Before this commit, the xxxChatOptions were not caught by reflection too, but it did not seem to cause any harm on a very simple sample.

IMO, XXXXRuntimeHints should add reflection hints for every xxxChatOptions. Happy to PR if this is this is acceptable.

By using the tracing agent, here is what works :

[
{
  "name":"org.springframework.ai.openai.OpenAiChatOptions",
  "allDeclaredFields":true,
  "allDeclaredClasses":true,
  "queryAllDeclaredMethods":true,
  "queryAllDeclaredConstructors":true,
  "methods":[{"name":"<init>","parameterTypes":[] }, {"name":"getFrequencyPenalty","parameterTypes":[] }, {"name":"getLogitBias","parameterTypes":[] }, {"name":"getLogprobs","parameterTypes":[] }, {"name":"getMaxCompletionTokens","parameterTypes":[] }, {"name":"getMaxTokens","parameterTypes":[] }, {"name":"getMetadata","parameterTypes":[] }, {"name":"getModel","parameterTypes":[] }, {"name":"getN","parameterTypes":[] }, {"name":"getOutputAudio","parameterTypes":[] }, {"name":"getOutputModalities","parameterTypes":[] }, {"name":"getParallelToolCalls","parameterTypes":[] }, {"name":"getPresencePenalty","parameterTypes":[] }, {"name":"getReasoningEffort","parameterTypes":[] }, {"name":"getResponseFormat","parameterTypes":[] }, {"name":"getSeed","parameterTypes":[] }, {"name":"getStop","parameterTypes":[] }, {"name":"getStore","parameterTypes":[] }, {"name":"getStreamOptions","parameterTypes":[] }, {"name":"getStreamUsage","parameterTypes":[] }, {"name":"getTemperature","parameterTypes":[] }, {"name":"getToolChoice","parameterTypes":[] }, {"name":"getTools","parameterTypes":[] }, {"name":"getTopLogprobs","parameterTypes":[] }, {"name":"getTopP","parameterTypes":[] }, {"name":"getUser","parameterTypes":[] }, {"name":"setModel","parameterTypes":["java.lang.String"] }, {"name":"setTemperature","parameterTypes":["java.lang.Double"] }]
}
]

Environment Spring Boot 3.4.3, liberika NIK 23.1.6.r21-nik

Steps to reproduce Use OpenAI API and compile with graalVM

Expected behavior should work out-of-the-box, like in M5. Adding reflections hints for chat options should be enough. Because today, only a few packages are scanned. Example for OpenAI :


    @Override
    public void registerHints(@NonNull RuntimeHints hints, @Nullable ClassLoader classLoader) {
        var mcs = MemberCategory.values();
        for (var tr : eval(findJsonAnnotatedClassesInPackage(OpenAiApi.class))) {
            hints.reflection().registerType(tr, mcs);
        }
        for (var tr : eval(findJsonAnnotatedClassesInPackage(OpenAiAudioApi.class))) {
            hints.reflection().registerType(tr, mcs);
        }
        for (var tr : eval(findJsonAnnotatedClassesInPackage(OpenAiImageApi.class))) {
            hints.reflection().registerType(tr, mcs);
        }
    }

But OpenAiChatOptions contains Jacksonannotations too.

Also, nitpick, but OpenAiApi.class, OpenAiAudioApi.class, OpenAiImageApi.class are all in the same package. Having multiple findJsonAnnotatedClassesInPackageis useless here ;)