Allow meta-annotations with Serializable for elements
What is your use-case and why do you need this feature?
Currently, annotating a property with an annotation having MetaSerializable instructs the serialization plugin to treat the annotated data class as serializable.
Doing that onto a field does't instruct the serialization plugin, as it misses the final serializer to be used: contextual ? custom ? something else ?
@MetaSerializable
@SerialInfo
annotation class MyAnnotation(val data: String)
@MyAnnotation("some content") // <-- the data class is treated as Serializable and is accessible from the `SerialDescriptor` annotations
data class MyData(
@MyAnnotation("some content") // <-- ERROR: Serializer has not been found for type 'MyType' as the serializer needs to be explicit or contextual
val theField: MyType,
)
Describe the solution you'd like
Allow @Serializable to be put on a meta-annotation, allowing us to unify the serializers with their possible configuration as we cannot pass params because of we need to provide a class.
I'm giving you an example: an avro fixed type requires some details to work properly, like its size in bytes. To configure the serializer to encode the content in 10 bytes, we can do like the following:
@Serializable
data class MyData(
@Serializable(with = ByteArrayFixedSerializer::class)
@AvroFixed(size = 10)
val theField: ByteArray,
)
Or even, more generically, for a given BigDecimal where we allow a maximum precision when encoding to a String:
@Serializable
data class MyData(
@Serializable(with = BigDecimalStringSerializer::class)
@DecimalPrecision(digits = 3)
val theField: BigDecimal,
@Serializable(with = AnotherDecimalSerializer::class)
@DecimalPrecision(digits = 3) // <--- This is useless as not handled by the AnotherDecimalSerializer implementation
val theField2: BigDecimal,
)
At the end, here would be the final code, making it clearer for the users IMO as it reduces the noise of needing many annotations:
@SerialInfo
@MetaSerializable
@Serializable(with = ByteArrayFixedSerializer::class)
annotation class AvroFixed(val size: Int)
@SerialInfo
@MetaSerializable
@Serializable(with = BigDecimalStringSerializer::class)
annotation class DecimalPrecision(val digits: Int)
@Serializable
data class MyData(
@AvroFixed(size = 10)
val theBytesField: ByteArray,
@DecimalPrecision(digits = 3)
val theDecimalField: BigDecimal,
@AvroFixed(size = 10)
@DecimalPrecision(digits = 3)
val wrongField: BigDecimal,// <--- ERROR: Doesn't compile as we are trying to apply 2 different serializers
@DecimalPrecision(digits = 3)
@Serializable(with = AnotherBigDecimalSerializer::class)
val example1: BigDecimal,// <--- AnotherBigDecimalSerializer takes precedence
@AvroFixed(size = 10)
val example1: BigDecimal,// <--- ERROR: Same as explicit `Serializable` annotation, where we are not able to annotate with a serializer of a different type
)
That's a great feature, but there is one big piece missing: passing property info to custom serializers. Currently, ByteArrayFixedSerializer would have no access to MyData.descriptor to actually understand that wrongField has AvroFixed with size = 10, even if we apply it automatically — because all info about properties is stored in the outer descriptor. So this feature requires at least designing passing serial info to custom serializers, e.g. in a form of adding Array<Annotation> to a custom serializer constructor.