What's the correct way to declare serializers? I ...
# serialization
c
What's the correct way to declare serializers? I have a class
Copy code
@Serializable(with = ObjectId.Serializer::class)
class ObjectId : Comparable<ObjectId> {
    …

    class Serializer : KSerializer<ObjectId> {
		override val descriptor: SerialDescriptor
			get() = PrimitiveSerialDescriptor("opensavvy.ktmongo.bson.types.ObjectId", PrimitiveKind.STRING)

		@LowLevelApi
		override fun serialize(encoder: Encoder, value: ObjectId) {
			encoder.encodeString(value.hex)
		}

		override fun deserialize(decoder: Decoder): ObjectId =
			decoder.decodeString().let(::ObjectId)
	}
}
and the code (in another module):
Copy code
val decoder = BsonDecoder(EmptySerializersModule(), this)
		return decoder.decodeSerializableValue(serializer(type) as KSerializer<T?>)
where
BsonDecoder : kotlinx.serialization.encoding.Decoder
, but on non-JVM platforms I get:
Copy code
kotlinx.serialization.SerializationException: Serializer for class 'ObjectId' is not found.
Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied.
To get enum serializer on Kotlin/Native, it should be annotated with @Serializable annotation.
To get interface serializer on Kotlin/Native, use PolymorphicSerializer() constructor function.
The serialization plugin is applied to both modules. I see I can explicitly specify it with:
Copy code
val module = SerializersModule {
			contextual(ObjectId::class, ObjectId.Serializer())
		}

		val decoder = BsonDecoder(module, this)
		return decoder.decodeSerializableValue(module.serializer(type) as KSerializer<T?>)
(even though the type is NOT used with
@Contextual
)—won't this mean that this code will break with user-provided types, though? I can't hardcode all the serializers that exist.
e
The way to share serializers is via the
SerializersModule
. Also on non-JVM platforms it seems you cannot use reflection to find serializers so you need to register your serializers
(I am not completely sure but found out Nav3 uses reflection to simplify its API on JVM but on Native, you must manually specify serializers 😞)
c
I don't get it. This function works, and does find the serializer, on all platforms.
Why would this one work, but the previous one wouldn't?
e
Hmm, no idea really.
j
This looks perfectly clean to me. Not sure what's going on - I've done a lot of multiplatform serialization and things like this one have always worked for me... Are you sure it's the same
ObjectId
type? What if you're accidentally using the MongoDB declared one instead of the one you declared?
c
It's in the
:bson-multiplatform
module, which doesn't have a dependency on the MongoDB one, so it shouldn't be possible that it's confusing them
The function is here and the test case is here
It reproduces in CI 😕 I was hoping it was an incremental compilation issue somehow, guess not
j
Hold on, you're using
KType
for this, not reification - I didn't notice that. I haven't tried
KType
usage.
c
Yes, i'm using reification to get the
KType
, then
serializer(t)
to get the serializer. I'm doing this to avoid having a serializer in the public API of the main module, since the other implementation doesn't use KotlinX.Serialization.
j
Ah, that makes sense. Unfortunately, you might not be able to get away with it. I don't have the knowledge to answer for sure though.
c
I think I understand why this wouldn't work but I don't understand why the other function I mentioned above does work, even though it does that too 🤔
Is there a way to create a
SerializerModule
and tell the plugin "hey, put all the serializers in you can find in there"?