-
Notifications
You must be signed in to change notification settings - Fork 36
Open
Labels
cantfixThis issue cannot be resolved at this point because of limitations in external libraries.This issue cannot be resolved at this point because of limitations in external libraries.
Description
Description
Consider the following toy example:
@Serializable
data class User(val name: String, val shoppingCart: ShoppingCart)
@Serializable(with = ShoppingCartSerializer::class)
data class ShoppingCart(val items: MutableList<Item>) {
val total: Double get() = items.sumOf { it.price }
}
@Serializable
data class Item(val name: String, val price: Double)
Where ShoppingCartSerializer
is a custom serializer, which serializes ShoppingCart
as a list:
class ShoppingCartSerializer : KSerializer<ShoppingCart> {
private val listSerializer = ListSerializer(Item.serializer())
override val descriptor: SerialDescriptor =
SerialDescriptor("org.example.ShoppingCart", listSerializer.descriptor)
override fun serialize(encoder: Encoder, value: ShoppingCart): Unit =
encoder.encodeSerializableValue(listSerializer, value.items)
override fun deserialize(decoder: Decoder): ShoppingCart =
ShoppingCart(decoder.decodeSerializableValue(listSerializer).toMutableList())
}
The following test, which should pass, does not:
val data = User(
"Alice",
ShoppingCart(mutableListOf(Item("T-Shirt", 20.0), Item("Boots", 50.0)))
)
@Test
fun testCustomCollectionXmlSerialization() {
val encodedXml = XML.encodeToString(data)
val decodedXml = XML.decodeFromString<User>(encodedXml)
assertEquals(
"""<User name="Alice"><Item name="T-Shirt" price="20.0"/><Item name="Boots" price="50.0"/></User>""",
encodedXml
)
assertEquals(data, decodedXml)
}
The first assert passes, i.e., encoding is correct.
The second assert, however, fails with:
Expected :User(name=Alice, shoppingCart=ShoppingCart(items=[Item(name=T-Shirt, price=20.0), Item(name=Boots, price=50.0)]))
Actual :User(name=Alice, shoppingCart=ShoppingCart(items=[Item(name=Boots, price=50.0)]))
I.e., decoding drops all items of the collection but the last.
Notes
- Using a standard "collection" (
List
,Set
,Array
, etc.) for the shopping cart directly instead of a class with a delegated serializer results in the decoding working as expected. - Changing the custom serializer's implementation to delegate to
SetSerializer
or any other "built-in" collection serializer results in the same incorrect behaviour. - The custom serializer's
deserialize
function is called once for each item of the collection, instead of only being called once for the whole collection. - The kotlinx.serialization JSON serializer has no problems with this example.
Reproduction
The code above showcasing the issue is available at: https://github.com/YarnSphere/xmlutil-custom-collection-serialization
Versions tested
0.86.3
with Kotlin1.9.24
0.90.0-RC2
with Kotiln2.0.0
Metadata
Metadata
Assignees
Labels
cantfixThis issue cannot be resolved at this point because of limitations in external libraries.This issue cannot be resolved at this point because of limitations in external libraries.