Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serialization failure in native mode when Kotlin companion object used #37957

Closed
shenbinglife opened this issue Dec 29, 2023 · 5 comments · Fixed by #38062
Closed

Serialization failure in native mode when Kotlin companion object used #37957

shenbinglife opened this issue Dec 29, 2023 · 5 comments · Fixed by #38062
Labels
Milestone

Comments

@shenbinglife
Copy link

shenbinglife commented Dec 29, 2023

Describe the bug

info

Build native on windows success, start success, but handle request failed.
One thing is : it's healty on non native build, using java -jar

quarkus + kotlin

source code

package org.acme.common


class ResponseData<T>(
    val code: Int = STATUS_CODE.SUCCESS.code,
    val msg: String = "",
    val data: T? = null,
) {
    companion object {
        fun success() = ResponseData<Unit>()
        fun <T> success(d: T) = ResponseData<T>(data = d)
        fun failure() = ResponseData<Unit>(code = STATUS_CODE.ERROR.code)

        fun failure(msg: String) = ResponseData<Unit>(code = STATUS_CODE.ERROR.code, msg = msg)
    }

    enum class STATUS_CODE(val code: Int) {
        SUCCESS(200),
        ERROR(500),
        OVERDUE(401),
        TIMEOUT(30000)
    }
}


@Path("system/menu")
class MenuController {

    @Inject
    lateinit var menuService: MenuService

    @Path("page")
    @GET
    fun page(@QueryParam("pageIndex") pageIndex: Int, @QueryParam("pageSize") pageSize: Int, @BeanParam menu: SysMenu) : ResponseData<*> {
        return ResponseData.success(menuService.page(menu, pageIndex, pageSize))
    }

    @Path("list")
    @GET
    fun list(): ResponseData<List<MenuOptions>> {
        return ResponseData.success(
            menuService.list()
        )
    }
}

ERROR log

2023-12-29 16:41:40,003 INFO  [io.quarkus] (main) rest-kotlin-quickstart 1.0.0-SNAPSHOT native (powered by Quarkus 3.6.3) started in 2.861s. Listening on: http://0.0.0.0:8849
2023-12-29 16:41:40,029 INFO  [io.quarkus] (main) Profile prod activated.
2023-12-29 16:41:40,030 INFO  [io.quarkus] (main) Installed features: [agroal, cdi, hibernate-orm, hibernate-orm-panache-kotlin, jdbc-mysql, kotlin, micrometer, narayana-jta, resteasy-reactive, resteasy-reactive-jackson, smallrye-context-propagation, vertx]
2023-12-29 16:41:42,361 ERROR [io.qua.ver.htt.run.QuarkusErrorHandler] (executor-thread-1) HTTP Request to /api/geeker/system/menu/33 failed, error id: e0c60a48-6434-4121-a0fc-841a147da518-1: java.lang.RuntimeException: kotlin.reflect.jvm.internal.KotlinReflectionInternalError: Could not compute caller for function: public final fun failure(): org.acme.common.ResponseData<kotlin.Unit> defined in org.acme.common.ResponseData.Companion[DeserializedSimpleFunctionDescriptor@1c4f851b] (member = null)
        at org.jboss.resteasy.reactive.server.core.ServerSerialisers.invokeWriter(ServerSerialisers.java:265)
        at org.jboss.resteasy.reactive.server.core.ServerSerialisers.invokeWriter(ServerSerialisers.java:195)
        at org.jboss.resteasy.reactive.server.core.serialization.FixedEntityWriter.write(FixedEntityWriter.java:28)
        at org.jboss.resteasy.reactive.server.handlers.ResponseWriterHandler.handle(ResponseWriterHandler.java:34)
        at io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.invokeHandler(QuarkusResteasyReactiveRequestContext.java:147)
        at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:147)
        at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:582)
        at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1538)
        at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
        at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base@21.0.1/java.lang.Thread.runWith(Thread.java:1596)
        at java.base@21.0.1/java.lang.Thread.run(Thread.java:1583)
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:832)
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.windows.WindowsPlatformThreads.osThreadStartRoutine(WindowsPlatformThreads.java:210)
Caused by: kotlin.reflect.jvm.internal.KotlinReflectionInternalError: Could not compute caller for function: public final fun failure(): org.acme.common.ResponseData<kotlin.Unit> defined in org.acme.common.ResponseData.Companion[DeserializedSimpleFunctionDescriptor@1c4f851b] (member = null)
        at kotlin.reflect.jvm.internal.KFunctionImpl$caller$2.invoke(KFunctionImpl.kt:98)
        at kotlin.reflect.jvm.internal.KFunctionImpl$caller$2.invoke(KFunctionImpl.kt:64)
        at kotlin.SafePublicationLazyImpl.getValue(LazyJVM.kt:107)
        at kotlin.reflect.jvm.internal.KFunctionImpl.getCaller(KFunctionImpl.kt:64)
        at kotlin.reflect.jvm.internal.KParameterImpl$type$1.invoke(KParameterImpl.kt:79)
        at kotlin.reflect.jvm.internal.KParameterImpl$type$1.invoke(KParameterImpl.kt:66)
        at kotlin.reflect.jvm.internal.ReflectProperties$LazySoftVal.invoke(ReflectProperties.java:70)
        at kotlin.reflect.jvm.internal.KTypeImpl.getJavaType(KTypeImpl.kt:46)
        at kotlin.reflect.jvm.ReflectJvmMapping.getJavaType(ReflectJvmMapping.kt:82)
        at com.fasterxml.jackson.module.kotlin.KotlinNamesAnnotationIntrospectorKt.isPossibleSingleString(KotlinNamesAnnotationIntrospector.kt:146)
        at com.fasterxml.jackson.module.kotlin.KotlinNamesAnnotationIntrospectorKt.filterOutSingleStringCallables(KotlinNamesAnnotationIntrospector.kt:150)
        at com.fasterxml.jackson.module.kotlin.KotlinNamesAnnotationIntrospectorKt.access$filterOutSingleStringCallables(KotlinNamesAnnotationIntrospector.kt:1)
        at com.fasterxml.jackson.module.kotlin.KotlinNamesAnnotationIntrospector.hasCreatorAnnotation(KotlinNamesAnnotationIntrospector.kt:86)
        at com.fasterxml.jackson.module.kotlin.KotlinNamesAnnotationIntrospector.access$hasCreatorAnnotation(KotlinNamesAnnotationIntrospector.kt:30)
        at com.fasterxml.jackson.module.kotlin.KotlinNamesAnnotationIntrospector$hasCreatorAnnotation$2.invoke(KotlinNamesAnnotationIntrospector.kt:97)
        at com.fasterxml.jackson.module.kotlin.KotlinNamesAnnotationIntrospector$hasCreatorAnnotation$2.invoke(KotlinNamesAnnotationIntrospector.kt:97)
        at com.fasterxml.jackson.module.kotlin.ReflectionCache.checkConstructorIsCreatorAnnotated(ReflectionCache.kt:99)
        at com.fasterxml.jackson.module.kotlin.KotlinNamesAnnotationIntrospector.hasCreatorAnnotation(KotlinNamesAnnotationIntrospector.kt:97)
        at com.fasterxml.jackson.databind.AnnotationIntrospector.findCreatorAnnotation(AnnotationIntrospector.java:1413)
        at com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair.findCreatorAnnotation(AnnotationIntrospectorPair.java:786)
        at com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair.findCreatorAnnotation(AnnotationIntrospectorPair.java:786)
        at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._addCreatorParam(POJOPropertiesCollector.java:722)
        at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._addCreatorParam(POJOPropertiesCollector.java:695)
        at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._addCreators(POJOPropertiesCollector.java:644)
        at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.collectAll(POJOPropertiesCollector.java:451)
        at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.getJsonValueAccessor(POJOPropertiesCollector.java:286)
        at com.fasterxml.jackson.databind.introspect.BasicBeanDescription.findJsonValueAccessor(BasicBeanDescription.java:258)
        at com.fasterxml.jackson.databind.ser.BasicSerializerFactory.findSerializerByAnnotations(BasicSerializerFactory.java:393)
        at com.fasterxml.jackson.databind.ser.BeanSerializerFactory._createSerializer2(BeanSerializerFactory.java:225)
        at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.createSerializer(BeanSerializerFactory.java:174)
        at com.fasterxml.jackson.databind.SerializerProvider._createUntypedSerializer(SerializerProvider.java:1503)
        at com.fasterxml.jackson.databind.SerializerProvider._createAndCacheUntypedSerializer(SerializerProvider.java:1451)
        at com.fasterxml.jackson.databind.SerializerProvider.findValueSerializer(SerializerProvider.java:556)
        at com.fasterxml.jackson.databind.SerializerProvider.findTypedValueSerializer(SerializerProvider.java:834)
        at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:307)
        at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1572)
        at com.fasterxml.jackson.databind.ObjectWriter._writeValueAndClose(ObjectWriter.java:1273)
        at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:1098)
        at io.quarkus.resteasy.reactive.jackson.runtime.serialisers.BasicServerJacksonMessageBodyWriter.writeResponse(BasicServerJacksonMessageBodyWriter.java:39)
        at org.jboss.resteasy.reactive.server.core.ServerSerialisers.invokeWriter(ServerSerialisers.java:227)
        ... 15 more

2023-12-29 16:41:42,545 INFO  [io.qua.htt.access-log] (executor-thread-1) 0:0:0:0:0:0:0:1 - - [29/Dec/2023:16:41:42 +0800] "GET /api/geeker/system/menu/33 HTTP/1.1" 500 72

Expected behavior

No response

Actual behavior

No response

How to Reproduce?

Just send http request to any Path

Output of uname -a or ver

No response

Output of java -version

17

Mandrel or GraalVM version (if different from Java)

GraalVM 21.0.1+12.1

Quarkus version or git rev

3.6.3

Build tool (ie. output of mvnw --version or gradlew --version)

gradle 8.5

Additional information

Gradle

plugins {
    id 'org.jetbrains.kotlin.jvm' version "1.9.21"
    id "org.jetbrains.kotlin.plugin.allopen" version "1.9.21"
    id 'io.quarkus'
}

repositories {
    repositories {
        maven { url 'https://maven.aliyun.com/repository/public' }
    }
    mavenCentral()
    mavenLocal()
}

dependencies {
    implementation enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}")
    implementation 'io.quarkus:quarkus-micrometer-registry-prometheus'
    implementation 'io.quarkus:quarkus-kotlin'
    implementation 'io.quarkus:quarkus-resteasy-reactive-jackson'
    implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
    implementation "org.jetbrains.kotlin:kotlin-reflect"
    implementation 'io.quarkus:quarkus-arc'
    implementation 'io.quarkus:quarkus-resteasy-reactive'
    implementation("io.quarkus:quarkus-narayana-jta")

    implementation("com.fasterxml.jackson.module:jackson-module-kotlin")

    // Hibernate ORM specific dependencies
    implementation 'io.quarkus:quarkus-hibernate-orm-panache-kotlin'

    // JDBC driver dependencies
    implementation("io.quarkus:quarkus-jdbc-mysql")

    testImplementation 'io.quarkus:quarkus-junit5'
    testImplementation 'io.rest-assured:rest-assured'

}

group 'org.acme'
version '1.0.0-SNAPSHOT'

java {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17
}

test {
    systemProperty "java.util.logging.manager", "org.jboss.logmanager.LogManager"
}
allOpen {
    annotation("jakarta.ws.rs.Path")
    annotation("jakarta.enterprise.context.ApplicationScoped")
    annotation("jakarta.persistence.Entity")
    annotation("io.quarkus.test.junit.QuarkusTest")
}

compileKotlin {
    kotlinOptions.jvmTarget = JavaVersion.VERSION_17
    kotlinOptions.javaParameters = true
}

compileTestKotlin {
    kotlinOptions.jvmTarget = JavaVersion.VERSION_17
}

操作系统

 ------------------------------------------------------------ Gradle 8.5 ------------------------------------------------------------ 
 Build time:   2023-11-29 14:08:57 UTC 
Revision:     28aca86a7180baa17117e0e5ba01d8ea9feca598  
Kotlin:       1.9.20 
Groovy:       3.0.17 
Ant:          Apache Ant(TM) version 1.10.13 compiled on January 4 2023 
JVM:          17.0.4.1 (Oracle Corporation 17.0.4.1+1-LTS-2) OS:          
 Windows 10 10.0 amd64
@shenbinglife shenbinglife added area/native-image kind/bug Something isn't working labels Dec 29, 2023
@quarkus-bot quarkus-bot bot added area/kotlin env/windows Impacts Windows machines labels Dec 29, 2023
Copy link

quarkus-bot bot commented Dec 29, 2023

/cc @Karm (mandrel), @galderz (mandrel), @geoand (kotlin), @zakkak (mandrel)

@geoand
Copy link
Contributor

geoand commented Jan 3, 2024

Can you please attach a sample project with a test that reproduces this behavior?

Thanks

@geoand geoand added the triage/needs-reproducer We are waiting for a reproducer. label Jan 3, 2024
@shenbinglife
Copy link
Author

https://github.com/shenbinglife/quarkus-kotlin-demo

reproduces this behavior

@geoand geoand removed triage/needs-reproducer We are waiting for a reproducer. env/windows Impacts Windows machines labels Jan 5, 2024
@geoand
Copy link
Contributor

geoand commented Jan 5, 2024

Thanks for the reproducer. As a temporary workaround you can annotate ResponseData with @RegisterForReflection.

What happens is that we register the whole class hierachy of ResponseData , but interestingly enough, registering the hierachy does not include nested classes...
On the other hand, when RegisterForReflection is used, nested classes are automatically added for reflection.

geoand added a commit to geoand/quarkus that referenced this issue Jan 5, 2024
@geoand geoand changed the title Could not compute caller for function: public final fun failure(): org.acme.common.ResponseData<kotlin.Unit> defined in org.acme.common.ResponseData.Companion[DeserializedSimpleFunctionDescriptor@1c4f851b] (member = null) Serialization failure in native mode when Kotlin companion object used Jan 5, 2024
@geoand
Copy link
Contributor

geoand commented Jan 5, 2024

#38062 fixes the problem

geoand added a commit that referenced this issue Jan 5, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
Add companion classes to Kotlin reflective hierarchy registration
@quarkus-bot quarkus-bot bot added this to the 3.7 - main milestone Jan 5, 2024
@gsmet gsmet modified the milestones: 3.7 - main, 3.6.5 Jan 9, 2024
gsmet pushed a commit to gsmet/quarkus that referenced this issue Jan 9, 2024

Verified

This commit was signed with the committer’s verified signature.
gsmet Guillaume Smet
Fixes: quarkusio#37957
(cherry picked from commit e185df8)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants