spring-attic / spring-native

Spring Native is now superseded by Spring Boot 3 official native support
https://docs.spring.io/spring-boot/docs/current/reference/html/native-image.html
Apache License 2.0
2.74k stars 356 forks source link

Document that -parameters javac flag is mandatory with native #1412

Closed jamesward closed 2 years ago

jamesward commented 2 years ago

Usually the id("org.springframework.boot") Gradle plugin adds:

kotlinOptions.javaParameters = true

But it doesn't in a Kotlin Multiplatform project (I think because the task is named differently than it expects).

Using a Kotlin data class in a Spring Data repo works fine on the JVM without this setting. But running via Spring Native, when trying to map the DB data, an exception is produced like:

java.lang.IllegalStateException: Required property null not found for class kotlinbars.common.Bar!
    at org.springframework.data.mapping.PersistentEntity.getRequiredPersistentProperty(PersistentEntity.java:161) ~[na:na]
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
    *__checkpoint ? Handler kotlinbars.server.WebApp#getBars(Continuation) [DispatcherHandler]
    *__checkpoint ? org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter [DefaultWebFilterChain]
    *__checkpoint ? HTTP GET "/api/bars" [ExceptionHandlingWebHandler]
Original Stack Trace:
        at org.springframework.data.mapping.PersistentEntity.getRequiredPersistentProperty(PersistentEntity.java:161) ~[na:na]
        at org.springframework.data.r2dbc.convert.MappingR2dbcConverter$RowParameterValueProvider.getParameterValue(MappingR2dbcConverter.java:717) ~[na:na]
        at org.springframework.data.mapping.model.SpELExpressionParameterValueProvider.getParameterValue(SpELExpressionParameterValueProvider.java:53) ~[na:na]
        at org.springframework.data.relational.core.conversion.BasicRelationalConverter$ConvertingParameterValueProvider.getParameterValue(BasicRelationalConverter.java:291) ~[na:na]
        at org.springframework.data.mapping.model.ReflectionEntityInstantiator.createInstance(ReflectionEntityInstantiator.java:73) ~[na:na]
        at org.springframework.data.mapping.model.ClassGeneratingEntityInstantiator.createInstance(ClassGeneratingEntityInstantiator.java:89) ~[na:na]
        at org.springframework.data.relational.core.conversion.BasicRelationalConverter.createInstance(BasicRelationalConverter.java:148) ~[na:na]
        at org.springframework.data.r2dbc.convert.MappingR2dbcConverter.createInstance(MappingR2dbcConverter.java:329) ~[na:na]
        at org.springframework.data.r2dbc.convert.MappingR2dbcConverter.read(MappingR2dbcConverter.java:126) ~[na:na]
        at org.springframework.data.r2dbc.convert.MappingR2dbcConverter.read(MappingR2dbcConverter.java:121) ~[na:na]
        at org.springframework.data.r2dbc.convert.EntityRowMapper.apply(EntityRowMapper.java:46) ~[na:na]
        at org.springframework.data.r2dbc.convert.EntityRowMapper.apply(EntityRowMapper.java:29) ~[na:na]
        at io.r2dbc.postgresql.PostgresqlResult.lambda$map$2(PostgresqlResult.java:124) ~[na:na]

I'm not sure if Spring Native can do anything to make this better / easier to troubleshoot but figure this might help others.

sdeleuze commented 2 years ago

Yeah with the JVM, it likely fallback on reading the .class resource with ASM which is not possible on native where the javaParameters is mandatory, so my feeling is that this issue is not specific to Spring Native but should be solved at Kotlin or Spring Boot Gradle plugin level.

At Kotlin level, maybe the multiplatform Gradle plugin should be configured in a way that allow Spring Boot plugin to detect and configure this option as it does with the JVM one.

If not possible, maybe Spring Boot Gradle plugin could configure the Kotlin multiplatform Gradle plugin to configure kotlinOptions.javaParameters = true properly but as stated on https://kotlinlang.org/docs/multiplatform.html it is still Alpha level so it may be too early for that.

@jamesward For the time behind, I can maybe add related documentation. Could you share how you configured it manually?

jamesward commented 2 years ago

Thank you. Here is my config: https://github.com/jamesward/kotlin-bars/blob/main/common/build.gradle.kts#L48-L50

sdeleuze commented 2 years ago

@wilkinsona Based on James feedback, it seems Spring Boot Gradle plugin configure javaParameters for Kotlin JVM plugin but not for the multiplaform one. If possible to qualify that without too much effort, could you share if that should be raised as an improvement request on Spring Boot side (which would be me preferred option given the manual config James did above)? If not, we will document it on Spring Native side.

wilkinsona commented 2 years ago

The common module doesn't appear to apply the Spring Boot plugin. Assuming that I've got that right, it's to be expected that javaParameters hasn't been configured automatically in that module. It looks to me like server is the only module with Boot's plugin applied.

sdeleuze commented 2 years ago

That could happen for Java multi-module projects as well, that's now properly documented.

jamesward commented 2 years ago

@wilkinsona I had the plugin in there and it wasn't working so I pulled it out. Let me know if you want a branch with that back in.

wilkinsona commented 2 years ago

Given that the common module doesn't appear to be a Spring Boot application, but instead a common shared library, I don't think it makes sense to apply Boot's plugin to it.