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

Support for serializer<@Contextual T> #2767

Open
UnknownJoe796 opened this issue Aug 9, 2024 · 3 comments
Open

Support for serializer<@Contextual T> #2767

UnknownJoe796 opened this issue Aug 9, 2024 · 3 comments
Labels

Comments

@UnknownJoe796
Copy link

UnknownJoe796 commented Aug 9, 2024

The following incomplete code cannot be used because @Contextual doesn't work in serializer<T>() .

This code would allow for very short definitions of server endpoints that handle serialization across multiple Content-Types.

inline fun <reified IN, reified OUT> ServerSystem.postHandler(action: (IN) -> OUT) {
    // Get the types for documentation purposes
    val inputType = serializer<IN>()
    val outputType = serializer<OUT>()
    // ... other setup ...
    // set up the underlying server library's request handler
    handler { request ->
        val format = Formats.lookup(headers["Content-Type"])
        val input = format.decodeFromBody(inputType, request.body)
        val output = action(input)
        return@handler HttpResponse(
            body = Formats.lookup(headers["Accept"]).encodeToBody(outputType, output)
        )
    }
}

// ...

val lookup = postHandler { input: @Contextual UUID ->
    database.get(input)
}

Attempting to use this crashes because the @Contextual annotation isn't carried through.

println(serializerOrNull(typeOf<@Contextual java.util.UUID>()))  // prints null

What I would expect is to get a ContextualSerializer for the type.

@xiaozhikang0916
Copy link
Contributor

The context is registered in the Serializers module, which means you need to provide a customized format. And if a customized format is provided, you may need not the @Contextual here.

@pdvrieze
Copy link
Contributor

@UnknownJoe796 As @xiaozhikang0916 says, you can just look up the serializer from the module. serializerOrNull is for statically determined serializers. Contextual needs a context.

@sandwwraith
Copy link
Member

I'm not sure what you are trying to achieve here since a) the @Contextual annotation has meaning only inside the @Serializable class b) ContextualSerializer is never returned from the serializer<T> function since it requires the SerializersModule to work. However, there are serializer<T> extensions on the SerializersModule as well, so I believe you want to do the following:

class Uuid

object UuidSerializer: KSerializer<Uuid> {
    override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("MyUuid", PrimitiveKind.STRING)
    override fun serialize(encoder: Encoder, value: Uuid) {
        TODO("Not yet implemented")
    }

    override fun deserialize(decoder: Decoder): Uuid {
        TODO("Not yet implemented")
    }
}

val myModule = SerializersModule {
    contextual(Uuid::class, UuidSerializer)
}

inline fun <reified IN> postHandler(action: (IN) -> Unit) {
    println(myModule.serializer<IN>().descriptor)
}

@Test
fun contextualDemo() {
    postHandler<Uuid> {  } // prints PrimitiveDescriptor(MyUuid)
} 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants