I'm trying to migrate our project to spring boot 3 using graalvm and we have a number of issues with AOT and gradle:
-
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
-
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
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