Rohen Giralt
06/29/2021, 2:28 PMval json = Json {
contextual(MyInterface::class, MyInterfaceSerializer)
}
but since that works on the KClass of the underlying type, I get an
kotlinx.serialization.SerializationException: Serializer for class 'MyInterfaceImpl' is not found.
I could use the encodeToString
method explicitly, rather than using contextual serialization, but since I’m using Ktor’s ContentNegotiation feature, I wouldn’t be able to retain any of its features (such as a correct Content-Type header, etc.) without a bunch more work.
Finally, I could also register each subtype polymorphically, but that seems like
• a lot of repeated code (since all serializers would be the same)
• a little bit of a breach of encapsulation (I’d like to have the serializer in a separate module, since the interface and its implementations don’t need to know about how they’re being displayed to the user, and vice versa)
Any ideas?dimitar_
06/29/2021, 3:20 PMdimitar_
06/29/2021, 3:21 PMrnett
06/29/2021, 8:30 PMdimitar_
06/29/2021, 9:45 PMpolymorphic
and @Serializable
on the implementation classes should be ok.dimitar_
06/29/2021, 9:46 PMrnett
06/29/2021, 9:46 PMRohen Giralt
06/30/2021, 3:12 PMinterface Program {
val name: String
val pid: Int
var isRunning: Bool
}
Different implementations might be a LocalCLIProgram
, which stops and runs a program via the command line; CloudProgram
, which runs in the cloud somewhere, etc.
Separately, I have a path (in the Ktor routing DSL)
get("/program/{name}") {
val program = programRepository[call.parameters["name"]]
call.respond(program)
}
What I’d like is for, no matter the concrete Program class, a request to /program/programName returns some JSON like
{
name: "programName",
pid: 1003
isRunning: false
}
The easiest way would be to have a custom SerializationStrategy
for the interface and just to use it to serialize any Program
I’m returning to the user, but Ktor’s implementation requires contextual serialization. KT-1317 I think would have provided the perfect solution, so I’ll leave my use case there.
I found some level of a workaround, though; I can manually serialize my Program
to a JsonObject and pass that to Ktor, still giving me all the benefits of Ktor Content Negotiation while also being able to serialize my classes how I want. I also wrote a simple extension function to make it easier:
suspend fun <T> ApplicationCall.respond(serializer: SerializationStrategy<T>, message: T) =
respond(Json.encodeToJsonElement(serializer, message))
and it seems to work so far. :-)Rohen Giralt
06/30/2021, 3:32 PM@Serializable
data class ProgramDisplay(
val name: String,
val pid: Int,
val isRunning: Boolean
) {
constructor(program: Program) : this(
program.name,
program.pid,
program.isRunning
)
}
and just respond with this separate ProgramDisplay
object rather than the Program
itself. This to some extent is a workaround for KT-1317; instead of serializing the object itself you convert it to a new one and serialize that.dimitar_
06/30/2021, 3:42 PMdimitar_
06/30/2021, 3:42 PMdimitar_
06/30/2021, 3:43 PM/program/cloud1
is:
{
"type": "cloudProgram",
"name": "cloud1",
"pid": 23,
"isRunning": false
}
dimitar_
06/30/2021, 3:46 PM