External/Contextual serializers are not supported
Ghedeon opened this issue · 11 comments
Description
External and Contextual serializers registered via SerialModule
are ignored at the moment.
Issue
Seems like serializer is obtained using the serializerByTypeToken(type)
method, which is not aware of registered serial modules.
Not sure if it's feasible to fix it in a reasonably clean manner without breaking changes but as quick check this line makes the test pass:
val loader = (serializer as FromString).format.context.getContextualOrDefault((type as Class<*>).kotlin)
To Reproduce
Failing Test (following existing deserialize()
test):
data class User(val name: String)
object UserSerializer : KSerializer<User> {
override val descriptor = PrimitiveDescriptor("User", STRING)
override fun deserialize(decoder: Decoder): User =
UserResponse.serializer().deserialize(decoder).run {
User(name = name)
}
override fun serialize(encoder: Encoder, value: User): Unit = TODO()
@Serializable
private data class UserResponse(val name: String)
}
@Before
fun setUp() {
val contentType = MediaType.get("application/json; charset=utf-8")
val retrofit = Retrofit.Builder()
.baseUrl(server.url("/"))
.addConverterFactory(Json {
serialModule = serializersModuleOf(User::class, UserSerializer)
}.asConverterFactory(contentType))
.build()
service = retrofit.create(Service::class.java)
}
@Test
fun deserialize() {
server.enqueue(MockResponse().setBody("""{"name":"Bob"}"""))
val user = service.deserialize().execute().body()!!
assertEquals(User("Bob"), user)
}
This seems like a kotlinx.serialization bug. Want to file one?
Your fix breaks cases such as List<User>
.
It probably breaks a few other things as well, was more like a quick check if I'm on the right track.
Not sure what to report to kotlinx.serialization tho. serializerByTypeToken()
works as advertised for Type
and for the all-inclusive case they have extensions like https://github.com/Kotlin/kotlinx.serialization/blob/e8a3bf2ad8fa1d11f3c2fe868f26806ba6e646e9/runtime/commonMain/src/kotlinx/serialization/SerialImplicits.kt#L67
but it works with reified, not sure how to make use of it here.
I would think the library needs a way to support contextual serializers with a Type
, not just Class
. It's also not clear how you would use contextual serializers with a type that itself has a generic parameter.
I'm not entirely sure that there's even a way to make generics work generally from the kotlinx.serialization side. Maybe some interesting application of JsonParametricSerializer
, but even then you could only register that for List::class
. I don't see a way around requiring end users to register a contextual serializer for List<User>
explicitly.
Yeah it was less a specific question and more meant to emphasize that this library is not the right place to handle these questions. The fact that you want User::class
handled differently is not a concern of this library. We just know to ask for whatever serializes User::class
from kotlinx.serialization and whether that's built-in, serializable, or backed by a custom serializer doesn't matter. I'm perfectly fine switching the API that the library uses to ask the question about what serializes a Type
, but implementing logic for things like contextual serializers or generic types is not the business I want to be in.
Agreed. I think providing an entirely separate contextual serializer-backed converter would probably be the way to go so you actually need to opt-in while also adding the caveat that generic types need to be registered manually in the serialModule
.
Maybe deprecating the existing functions that take StringFormat
/ByteFormat
and replace with a function that takes a JsonConfiguration
directly?
The library knows nothing about the chosen serialization format so we cannot use anything tied to a specific format. I'll have to look into how SerialModule
is used.
@JakeWharton, I think this issue could be resolved via Kotlin/kotlinx.serialization#803, which should be relatively easy to implement.
So where does this stand now they they went H.A.M. on their codebase and everything has been moved and/or renamed?
Want to send a PR with the fix?
Good question. I should have some time to look into the changes to make sure this feature can be implemented. If so I'll try and get a PR pushed.
Released in 0.7.0