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

Intrinsics for serializer() function #1348

Closed
qwwdfsad opened this issue Feb 20, 2021 · 18 comments
Closed

Intrinsics for serializer() function #1348

qwwdfsad opened this issue Feb 20, 2021 · 18 comments
Assignees
Labels
compiler-plugin intrinsics Problems with intrinsics of serializer() function

Comments

@qwwdfsad
Copy link
Member

Currently, our format API can be used in two ways: with explicit serializer, and with inferred from the type parameters, for exaple:

// Explicit
val jsonString = Json.decodeToString(MyClass.serializer(), MyClass(...))
val data = Json.encodeFromString(MyClass.serializer(), jsonString)

// Implicit
val jsonString = Json.decodeToString(MyClass(...)) // Inferred type-parameter T
val data = Json.encodeFromString<MyClass>(jsonString) // Or data: MyClass = Json.encodeFromString(sonString)

We always promote usages of the latter, because it has the same meaning, but in the meantime is more expressive and concise. It is based on the experimental typeOf function and we are able to retrieve the serializer using KType.

Unfortunately, it has two downsides:

Proposal

Introduce the notion of intrinsic to the serialization plugin. serializer() and serializerOfNull are going to be evaluated in the compile-time. Additionally, this evaluation will happen transitively through all reified inline functions that leverage serializer<T>.

To properly resolve context-specific serializers, more compact contextualOrDefault(defaultSerializer) function will be used instead.

@NorbertSandor
Copy link

When may we expect this proposal to be implemented?

@sandwwraith
Copy link
Member

@NorbertSandor We can't give any particular timeframe for now, but we aim to provide this before Kotlin 1.6

@sdeleuze
Copy link

sdeleuze commented Jan 4, 2022

If possible we would love to get it in Kotlin 1.7 for Spring needs, especially related to GraalVM native images.

@snowe2010
Copy link

seems like this has been bumped several times. What work needs to be done here? Is there anything the community can do to help out?

@sandwwraith
Copy link
Member

@snowe2010 The work has to be done in the compiler plugin — currently, they can't provide intrinsics, and we have to change that. I'm working at this task at the moment, and I hope I will be able to present results soon

@snowe2010
Copy link

@sandwwraith ah, I see. thank you for your work! good luck!

@PedroAlvarado
Copy link

It's been some time since the last update on this issue. Is it fair to expect this fixed some time next year?

@qwwdfsad
Copy link
Member Author

qwwdfsad commented Dec 5, 2022

It's already implemented in the not-yet-released Kotlin 1.8.0, stay tuned!

@sdeleuze
Copy link

sdeleuze commented Jan 2, 2023

Is it expected to be fixed with kotlinx.serialization 1.4.1 and Kotlin 1.8.0, or do we need to wait a new release of kotlinx.serialization?

@sandwwraith
Copy link
Member

sandwwraith commented Jan 2, 2023

As there are some runtime functions this functionality depends on, intrinsics should be working once 1.5.0-RC is released

@morki
Copy link

morki commented Feb 6, 2023

I just tested it with Ktor, kontlinx.serialization 1.5.0-RC and plugin version 1.8.10 and it is not still does not work. Serialization fails in native image without reflection and Intrinsics are not used in generated JARs.

@sandwwraith Is there anything else one need to configure to make it work?

@sandwwraith
Copy link
Member

@morki Which function do you use? 1.8.0, which is used to compile 1.5.0-RC, has some subtle bug, and as a result, the Json.encodeToString function is not intrinsified. serializer<T>(), however, still should work with 1.8.x + 1.5.0-RC.

@morki
Copy link

morki commented Feb 7, 2023

@sandwwraith thank you for quick response. My code is actually like this:

@Resource("/login")
@Serializable
data class LoginRoute(
    val state: String? = null,
)

fun Route.registerLoginRoutes() {
    get<LoginRoute> {
      // TODO
    }
}

which calls function Route.get which looks like this:

public inline fun <reified T : Any> Route.get(
    noinline body: suspend PipelineContext<Unit, ApplicationCall>.(T) -> Unit
): Route {
    lateinit var builtRoute: Route
    resource<T> {
        builtRoute = method(HttpMethod.Get) {
            handle(body)
        }
    }
    return builtRoute
}

and it calls function Route.resource which looks like this:

public inline fun <reified T : Any> Route.resource(noinline body: Route.() -> Unit): Route {
    val serializer = serializer<T>()
    return resource(serializer, body)
}

and it calls serializer function.

@morki
Copy link

morki commented Feb 7, 2023

@sandwwraith sorry, my fault, it is because Ktor is precompiled with Kotlin 1.7.20, when I compiled locally and pushed to Maven local, all works fine :)

@snowe2010
Copy link

Hm. I was seeing the issue still as well, but I think it's because we're using the encode and decode methods.

@sandwwraith
Copy link
Member

This feature is fully functional now. Requirements are Kotlin 1.8.10+ and serialization core runtime 1.5.0+.

@sandwwraith sandwwraith added the intrinsics Problems with intrinsics of serializer() function label Mar 16, 2023
@sandwwraith
Copy link
Member

In an unlikely occasion of problems with replacement, inlining can be disabled with freeCompilerArgs += ["-P", "plugin:org.jetbrains.kotlinx.serialization:disableIntrinsic=true"].

@OliverO2
Copy link

Ran a series of tests with ProtoBuf on JVM and Js. Works like a charm!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler-plugin intrinsics Problems with intrinsics of serializer() function
Projects
None yet
Development

No branches or pull requests

8 participants