I'm trying to migrate our project to spring boot 3 using graalvm and we have a number of issues with AOT and gradle:

  1. When using nativeRun (to make sure our microservices will bootstrap): Exception in thread "main" java.lang.reflect.UndeclaredThrowableException at org.springframework.util.ReflectionUtils.rethrowRuntimeException(ReflectionUtils.java:147) at org.springframework.boot.SpringApplication.handleRunFailure(SpringApplication.java:794) at org.springframework.boot.SpringApplication.run(SpringApplication.java:321) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1291) at com.pwc.uk.ica.platform.services.clients.ClientAppKt.main(ClientApp.kt:21) Caused by: java.lang.ClassNotFoundException: org.springframework.security.config.web.server.ServerHttpSecurity$AuthorizeExchangeSpec

  2. When using bootRun, we get the following error:

Process 'command '/Library/Java/JavaVirtualMachines/graalvm-ce-java17-22.3.0/Contents/Home/bin/java'' finished with non-zero exit value

Our tests pass (although given our extensive use of mockito, we exclude tests from graal native compilation)

Comment From: mhalbritter

This looks like that your application doesn't work at all and is not related to native. Please remove the native build tools from your project and try bootRun again. Then post the whole output here.

Comment From: ianmichell

Actually this is not the case - this has been working fine on JVM.

I had a method that setup my baseline security which expected:

fun setupRoutes(spec: ServerHttpSecurity.AuthorizeExchangeSpec) ...

When I removed the method and changed it to a lambda it compiled (although I have other issues now with nativeImage).

To me this appears to be something to do with not liking inner classes - specifically related to kotlin.

Comment From: mhalbritter

If you'd like us to spend some time investigating, please take the time to provide a complete minimal sample (something that we can unzip or git clone, build, and deploy) that reproduces the problem.

Comment From: ianmichell

I'll see if I can replicate the issue in a spring boot demo project.

Comment From: ianmichell

I have attached a demo from spring initialiser with the problematic code. I have no idea if this will actually run in normal jar mode, but it does reproduce the error in question.

I am on macos 12.6, using gradle 7.5.1 and graalvm: 22.3.0

demo.zip

Comment From: mhalbritter

This is enough to trigger the error:

    @Bean
    fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
        return http.authorizeExchange { setupSecurity(it) }.build()
    }

    private fun setupSecurity(spec: ServerHttpSecurity.AuthorizeExchangeSpec) {
        spec.pathMatchers("/actuator/**").permitAll()
    }

When writing this in Java, it works.

Here's the stacktrace: stacktrace.txt

Comment From: mhalbritter

Rewriting it this way doesn't trigger the error:

    @Bean
    fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
        return http.authorizeExchange { spec -> spec.pathMatchers("/actuator/**").permitAll() }.build()
    }

Comment From: ianmichell

Could it be a bit of incompatibility between Graal and Kotlin as i get other errors as well?


APPLICATION FAILED TO START


Description:

Failed to bind properties under 'ica.platform.security.routes[0]' to com.pwc.uk.ica.platform.security.common.RouterRule:

Reason: java.lang.NullPointerException: Parameter specified as non-null is null: method com.pwc.uk.ica.platform.security.common.RouterRule.<init>, parameter method

Works in standard JVM and bootRun with graalVM too

Comment From: mhalbritter

I'm not really sure what's going on here, as this is enough to trigger the error:

    @Bean
    fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
        return http.build()
    }

    private fun setupSecurity(spec: ServerHttpSecurity.AuthorizeExchangeSpec) {
        spec.pathMatchers("/actuator/**").permitAll()
    }

Note that setupSecurity is never referenced.

It looks like (from the stacktrace) that some BeanFactoryRegistryPostProcessor inspects the class which contains the setupSecurity method, which triggers at org.springframework.core.MethodParameter$KotlinDelegate.getGenericReturnType, which then uses kotlin.reflect.jvm.ReflectJvmMapping.getKotlinFunction to inspect the method. This fails, as kotlin.reflect.jvm.internal.KDeclarationContainerImpl.parseType tries to load org.springframework.security.config.web.server.ServerHttpSecurity$AuthorizeExchangeSpec which isn't in the image?!

Comment From: ianmichell

Could be related.

https://github.com/oracle/graal/issues/2306

I'll setup a custom graalvm test and see if I can resolve it this way

Comment From: mhalbritter

Okay, so reflection with Kotlin in a native-image is weird. When using ResolableType.forMethodReturnType on a Kotlin method, it essentially needs reflection metadata for all methods in that class. (Actually it's more complicated - the methods are iterated until a matching one is found. The iteration order is the alphabetical sort, but that may be an implementation detail). I have a showcase project here: https://github.com/mhalbritter/kotlin-graalvm-reflection which goes into more detail.

That's why it fails if the unused private method setupSecurity is present and it works when that method is refactored into a lambda. I guess it also works if you rename the method to zsetupSecurity to ensure it's iterated last.

There's definitely something missing here, and I tend to declare that as a native-image incompatibility in Kotlin. Not sure we can do something here.

@sdeleuze What do you think?

Comment From: mhalbritter

I've filed a framework issue for that: https://github.com/spring-projects/spring-framework/issues/29663

Comment From: sdeleuze

I will have a deeper look and provide my feedback on the issue you created on Framework side.

Comment From: mhalbritter

As explained in https://github.com/spring-projects/spring-framework/issues/29663, Spring Framework will generate resource hints for all methods on @Configuration classes written in Kotlin. Closing this issue in favor of https://github.com/spring-projects/spring-framework/issues/29663