xmlutil
xmlutil copied to clipboard
Problem with maps
Hi Fist of all, thank your work, I love. I have a problem serialization a map, from Kotlin to XML. I don't know if I am wrong or is a problem. I have this class
@Serializable
@SerialName("estadistica")
data class Estadistica(
@Serializable(with = UUIDSerializer::class)
val id: UUID = UUID.randomUUID(),
@XmlElement(true)
val resumenes: Map<String, Resumen> = mapOf(),
@Serializable(with = LocalDateTimeSerializer::class)
val createdAt: LocalDateTime = LocalDateTime.now(),
)
I have a problem with the map. If I change map for list, I don´t have any problem, but with map I have the exception
this is my code
val informeXml = myScope.launch {
logger.debug { "Guardando informe en XML..." }
val informe = InformeDto(
estadisticas = listOf(
EstadisticaDto(
resumenes = mapOf(
"a" to ResumenDto(tipo = "NO2"),
"b" to ResumenDto(tipo = "CO"),
"c" to ResumenDto(tipo = "Ozone"),
)
),
)
)
val xml = XML {
indentString = " "
autoPolymorphic = true
}
xmlFile.writeText(xml.encodeToString(informe))
}
informeXml.join()
No problem if change map for list
The exception is:
Exception in thread "DefaultDispatcher-worker-5" java.lang.IndexOutOfBoundsException: Index 2 out of bounds for length 2
at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:266)
at java.base/java.util.Objects.checkIndex(Objects.java:359)
at java.base/java.util.ArrayList.get(ArrayList.java:427)
at nl.adaptivity.xmlutil.serialization.structure.XmlCompositeDescriptor.getElementDescriptor(XmlDescriptor.kt:670)
at nl.adaptivity.xmlutil.serialization.XmlEncoderBase$TagEncoder.encodeSerializableElement(XMLEncoder.kt:396)
at kotlinx.serialization.internal.MapLikeSerializer.serialize(CollectionSerializers.kt:122)
at nl.adaptivity.xmlutil.serialization.XmlEncoderBase$TagEncoder$encodeSerializableElement$3.invoke(XMLEncoder.kt:424)
at nl.adaptivity.xmlutil.serialization.XmlEncoderBase$TagEncoder$encodeSerializableElement$3.invoke(XMLEncoder.kt:424)
at nl.adaptivity.xmlutil.serialization.XmlEncoderBase$TagEncoder.endStructure(XMLEncoder.kt:568)
at dto.EstadisticaDto$$serializer.serialize(EstadisticaDto.kt:11)
at dto.EstadisticaDto$$serializer.serialize(EstadisticaDto.kt:11)
at nl.adaptivity.xmlutil.serialization.XmlEncoderBase$ListEncoder.encodeSerializableElement$xmlutil_serialization(XMLEncoder.kt:940)
at nl.adaptivity.xmlutil.serialization.XmlEncoderBase$TagEncoder.encodeSerializableElement(XMLEncoder.kt:396)
at kotlinx.serialization.internal.CollectionLikeSerializer.serialize(CollectionSerializers.kt:69)
at nl.adaptivity.xmlutil.serialization.XmlEncoderBase$TagEncoder$encodeSerializableElement$3.invoke(XMLEncoder.kt:424)
at nl.adaptivity.xmlutil.serialization.XmlEncoderBase$TagEncoder$encodeSerializableElement$3.invoke(XMLEncoder.kt:424)
at nl.adaptivity.xmlutil.serialization.XmlEncoderBase$TagEncoder.endStructure(XMLEncoder.kt:568)
at dto.InformeDto$$serializer.serialize(InformeDto.kt:17)
at dto.InformeDto$$serializer.serialize(InformeDto.kt:17)
at nl.adaptivity.xmlutil.serialization.XML.encodeToWriter(XML.kt:259)
at nl.adaptivity.xmlutil.serialization.XML.encodeToWriter(XML.kt:205)
at nl.adaptivity.xmlutil.serialization.XML.encodeToString(XML.kt:149)
at nl.adaptivity.xmlutil.serialization.XML.encodeToString(XML.kt:136)
at dto.InformeDtoKt.writeToXmlFile(InformeDto.kt:41)
at controllers.R2D2Controller$saveData$2$informeXml$1.invokeSuspend(R2D2Controller.kt:163)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@2b0cb275, Dispatchers.IO]
07:31:27.587 [DefaultDispatcher-worker-5] DEBUG controllers.R2D2Controller - Datos salvados exitosamente
Tiempo de procesamiento: 320ms
Process finished with exit code 0
Could you help me? Thanks!
I've had a preliminary look here. While there is clearly a bug with the descriptors (that I've fixed in dev), there is a broader problem in that maps basically aren't supported, and are not that trivial to support nicely. They are serialized with interleaved keys and values and that is just not correct in XML. I'm working on solving that but doing that in a way that I would know is robust is a bit tricky so it will take a bit. In the meantime, there may be some mileage in serializing maps as lists of "entries".
Oh thank you again. Yes a List of entries was my solution. Thank you again
I've implemented it on the development branch. It should also be available soon as snapshot (this is the only difference with the release). I haven't tested yet with polymorphic keys or values although it should work. It is also configurable using a custom/overriding policy, but there are as yet no easy-configuration annotations or such implemented. The default implementation uses the list elision setting, and if the key can be written as attribute (ie. it is like a primitive) and that property name is not present in the value it will write it as a tag with the value, but the key additional.
There is one limitation in that map serialization requires keys to be read before values. In the case that the key is a tag (and there thus is a wrapping entry), this could be out of order. This is not yet supported by the format (it requires reading the value content into memory, storing it and then retrieving the key. Handling of unexpected tag content is not done well yet either.
Thank you so much! i don't try it. I will wait to stable version. But I know it will be a fantastic feature :)
Now released in 0.85.0.