Description
What is your use-case and why do you need this feature?
I need to use JSON to encode and decode 2d arrays of x/y coordinates
@Serializable
data class Coordinates(
val x: Int,
val y: Int,
)
By default, the JSON encoding is not size-optimal
{ "x": 1, "y": 2 }
Encoding a coordinate as a tuple (a fixed-length array, with fixed types per position, see the TypeScript docs) would make the messages more compact, and save a lot of space and improve processing speeds.
[1, 2]
There are other data structures I'd like to encode as well. For example, some information for each coordinate.
@Serializable
data class CoordinatesDetails(
val x: Int,
val y: Int,
private val colour: String,
private val active: Boolean,
) {
...
}
Again, this would save a lot of space if I could en/decode it as a tuple
[1, 2, "red", true]
{ "x": 1, "y": 2, "colour": "red", "active": true }
Describe the solution you'd like
I've created a 'tuple descriptor builder' https://github.com/adamko-dev/kotlinx-serialization-typescript-generator/blob/main/docs/tuples.md
// tuple descriptor builder example
@Serializable(with = Coordinates.Serializer::class)
data class Coordinates(
val x: Int,
val y: Int,
) {
object Serializer : TupleSerializer<Coordinates>(
"Coordinates",
{
element(Coordinates::x)
element(Coordinates::y)
}
) {
override fun tupleConstructor(elements: Iterator<*>): Coordinates {
val x = requireNotNull(elements.next() as? Int)
val y = requireNotNull(elements.next() as? Int)
return Coordinates(x, y)
}
}
}
This is quite finickity though, and also it's bugged. Under the hood it requires buildSerialDescriptor
, because buildClassSerialDescriptor
doesn't allow setting the structure kind to be LIST
.
My custom tuple-serializer would be much easier if I could
- retain the plugin-generated serializer Keep access to plugin generated serializer when mark class with @Serializable(with = MySerializer) #1169
- override the serial kind of the plugin-generated descriptor and change it from
CLASS
toLIST
.
Alternatively, it would be even easier if I could tell the compiler plugin to generate a descriptor as usual, except just change the 'kind' of the descriptor.
@Serializable(kind = StructureKind.LIST)
data class Coordinates(
...
Finally, another option is to add an arg to buildClassSerialDescriptor
public fun buildClassSerialDescriptor(
serialName: String,
serialKind: StructureKind = StructureKind.CLASS, // new arg, with a default
vararg typeParameters: SerialDescriptor,
builderAction: ClassSerialDescriptorBuilder.() -> Unit = {}
):
...