You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I'm writing Kafka serdes where null has a very special meaning (tombstones). I do want to keep the nullability information for the type parameters, but I don't want the serializer to support null. The problem is that it's not possible to unwrap a serializer that has been wrapped with nullability. As such I'm forced to check every result the serializer or deserializer gives me to ensure it doesn't return null, and fail at runtime. Here's a deserializer example:
@OptIn(ExperimentalSerializationApi::class)
publicclassJsonDeserializer<T>(
privatevalstrategy:DeserializationStrategy<T & Any>,
json:Json? = null,
) : Deserializer<T> {
privateval json = json ?:JSONinit {
// We cannot do this, because of the reified factory method.// require(!strategy.descriptor.isNullable)
}
overridefundeserialize(topic:String?, data:ByteArray?): T? {
if (data ==null) {
returnnull
}
val result =try {
json.decodeFromStream(strategy, ByteArrayInputStream(data))
} catch (cause: kotlinx.serialization.SerializationException) {
throwSerializationException("Kotlinx JSON deserialization failed", cause)
}
@Suppress("SENSELESS_COMPARISON")
if (result ==null) {
throwSerializationException(
"Kotlinx JSON deserialization returned null which is forbidden as it's not "+"possible anymore to tell the difference between a tombstone and a datum "+"that is null, the actual error is with the producer of the data, since it "+"should never have produced a serialized literal JSON null value in the "+"first place"
)
}
return result
}
}
publicinlinefun <reifiedT> JsonDeserializer(json:Json? = null): JsonDeserializer<T> =JsonDeserializer(serializer(), json)
Users who use the constructor with a manually created strategy get a serializer with no nullability, but those who use the reified factory method always get a serializer that supports null. The T & Any on the DeserializationStrategy is ignored entirely by the serializer() call.
JsonDeserializer<String>(serializer()) // 🟢 all goodJsonDeserializer<String?>(serializer<String>()) // 🟡 ok but inconvenientJsonDeserializer<String>() // 🟢 all goodJsonDeserializer<String?() // 🔴 not good
Adding an Any bound to T would obviously work, but it would mean that it's not possible anymore to automatically create serdes for topics where the key and/or value is actually nullable (supports tombstones).
I haven't looked into why it's possible that I can pass a KSerializer<T> to a DeserializationStrategy<T & Any> and whether this is actually an issue of this library or a Kotlin issue. But, it's strange…
I have no idea on how to work around this. Obviously I could use reflection and unwrap the inner serializer from the NullableSerializer, but that wouldn't help me with custom serializers that might be created from the serializer() factory method where isNullable is true but no inner serializer exists that could be unwrapped.
I'm not sure if it's even possible to do anything about this here, and I would have used the GitHub discussion feature if available. Anyway, looking for any help, ideas, and insights.
The text was updated successfully, but these errors were encountered:
I'm writing Kafka serdes where
null
has a very special meaning (tombstones). I do want to keep the nullability information for the type parameters, but I don't want the serializer to supportnull
. The problem is that it's not possible to unwrap a serializer that has been wrapped with nullability. As such I'm forced to check every result the serializer or deserializer gives me to ensure it doesn't returnnull
, and fail at runtime. Here's a deserializer example:Users who use the constructor with a manually created
strategy
get a serializer with no nullability, but those who use the reified factory method always get a serializer that supportsnull
. TheT & Any
on theDeserializationStrategy
is ignored entirely by theserializer()
call.Adding an
Any
bound toT
would obviously work, but it would mean that it's not possible anymore to automatically create serdes for topics where the key and/or value is actually nullable (supports tombstones).I haven't looked into why it's possible that I can pass a
KSerializer<T>
to aDeserializationStrategy<T & Any>
and whether this is actually an issue of this library or a Kotlin issue. But, it's strange…I have no idea on how to work around this. Obviously I could use reflection and unwrap the inner serializer from the
NullableSerializer
, but that wouldn't help me with custom serializers that might be created from theserializer()
factory method whereisNullable
istrue
but no inner serializer exists that could be unwrapped.I'm not sure if it's even possible to do anything about this here, and I would have used the GitHub discussion feature if available. Anyway, looking for any help, ideas, and insights.
The text was updated successfully, but these errors were encountered: