-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Parse children as Element or Text / CDATA #253
Comments
You probably need to make sure to use autopolymorphic mode. I've created a test for this. The following code works for me (note that I chose to parse content of Adverifications as Element rather than creating a class for verification). class StringOrCompositePolymorphism253 {
val xml = XML(ExtensionDto.module()) { recommended_0_90_2() }
@Test
fun testParse() {
val result = xml.decodeFromString<List<ExtensionDto>>(SAMPLE, QName("Extensions"))
assertEquals(2, result.size)
assertEquals("{\"savedData\":\"\"}", assertIs<String>(result[0].value[0]).trim())
for (e in result[1].value) {
if(e is String) assertEquals("", e.trim())
}
val e2 = result[1].value.filterIsInstance<AdVerificationsDto>().single()
assertEquals(1, e2.verifications?.size)
assertIs<Element>(e2.verifications?.single())
}
@Serializable
@SerialName("Extension")
data class ExtensionDto(
val source: String? = null,
val type: String? = null,
@XmlValue
var value: List<@Polymorphic Any> = listOf()
) {
companion object {
fun module() = SerializersModule {
polymorphic(Any::class) {
subclass(String::class)
subclass(AdVerificationsDto::class)
}
}
}
}
@Serializable
@SerialName("AdVerifications")
data class AdVerificationsDto(
@XmlElement(true)
@XmlValue
var verifications: MutableList<Element>? = mutableListOf()
)
val SAMPLE = """
|<Extensions>
| <Extension source="mySource">
| <![CDATA[{"savedData":""}]]>
| </Extension>
| <Extension type="AdVerifications">
| <AdVerifications>
| <Verification vendor="Something">
| <JavaScriptResource apiFramework="omid" browserOptional="true">
| <![CDATA[https://google.com/video.js]]>
| </JavaScriptResource>
| <VerificationParameters>
| <![CDATA[{"key":"21649"}]]>
| </VerificationParameters>
| </Verification>
| </AdVerifications>
| </Extension>
|</Extensions>
""".trimMargin()
} |
configuration that does not have autopolymorphism enabled.
Hello, It solved my issue by using the autoPolymorphic parameter that I missed. My final configuration looks like this after updating to: 0.90.3 @OptIn(ExperimentalXmlUtilApi::class)
val parser = XML(ExtensionDto.module()) {
policy = DefaultXmlSerializationPolicy(formatCache = DefaultFormatCache()) {
autoPolymorphic = true
isStrictAttributeNames = false
}
} Thanks a lot for your time and help. |
Autopolymorphic is needed here, otherwise it expects a wrapper for polymorphism. The reason it is not the default is for compatibility. |
Thanks for the precisions, and for pointing out the It seems better to use the Do you know if the performance cost is still better than having no cache at all in most cases ? |
The multithreading version uses threadlocal "copies" of the cache. The "local" cache is acquired once at the start of (de)serialization as that by necessity is within the same thread. As such the overhead should be fairly limited as compared to not having the safety. What the overhead is of the cached (metadata) process depends a bit on the structure of your files/documents. For XML Schema the initial creation of the metadata is significant, but xml schema is hardly a simple document format. |
Thanks for the details it works fine with the defaultSharedFormatCache on our side. But I found a new issue when there is an optional Element like: <Extension type="geo">
<Country>IE</Country>
</Extension> I tried to add a defaultDeserializer to the polymorphic @Serializable
@SerialName("Extension")
data class ExtensionDto(
val source: String? = null,
val type: String? = null,
@XmlValue
var value: List<@Polymorphic Any> = listOf()
) {
companion object {
fun module() = SerializersModule {
polymorphic(Any::class) {
defaultDeserializer { Unknown.serializer() }
subclass(String::class)
subclass(AdVerificationsDto::class)
}
}
}
}
@Serializable
class Unknown I also tried using a wrapper but couldn't solve the issue with the string type as I can't use it as a subclass of a specific wrapper type. The error I get when trying to parse this country field (that we don't handle ATM so just returning null or an empty class like the Unknown one would be fine): error (exception=nl.adaptivity.xmlutil.serialization.XmlParsingException: Invalid XML value at position: 137:23: No XmlSerializable found to handle unrecognized value tag Country in polymorphic context)
nl.adaptivity.xmlutil.serialization.XmlParsingException: Invalid XML value at position: 137:23: No XmlSerializable found to handle unrecognized value tag Country in polymorphic context
at nl.adaptivity.xmlutil.serialization.XmlDecoderBase.deserializeSafe(XMLDecoder.kt:2229)
at nl.adaptivity.xmlutil.serialization.XmlDecoderBase$AnonymousListDecoder.decodeSerializableElement(XMLDecoder.kt:1701)
at kotlinx.serialization.encoding.CompositeDecoder$DefaultImpls.decodeSerializableElement$default(Decoding.kt:538)
at kotlinx.serialization.internal.CollectionLikeSerializer.readElement(CollectionSerializers.kt:80)
at kotlinx.serialization.internal.AbstractCollectionSerializer.readElement$default(CollectionSerializers.kt:51)
at kotlinx.serialization.internal.AbstractCollectionSerializer.merge(CollectionSerializers.kt:36)
at nl.adaptivity.xmlutil.serialization.XmlDecoderBase$TagDecoderBase.decodeSerializableElement(XMLDecoder.kt:900)
at com.dailymotion.adsharedsdk.feature.vastparser.data.dto.ExtensionDto$$serializer.deserialize(VastDto.kt:168)
at com.dailymotion.adsharedsdk.feature.vastparser.data.dto.ExtensionDto$$serializer.deserialize(VastDto.kt:168)
at nl.adaptivity.xmlutil.serialization.XmlDecoderBase.deserializeSafe(XMLDecoder.kt:111)
at nl.adaptivity.xmlutil.serialization.XmlDecoderBase$AnonymousListDecoder.decodeSerializableElement(XMLDecoder.kt:1701)
at kotlinx.serialization.encoding.CompositeDecoder$DefaultImpls.decodeSerializableElement$default(Decoding.kt:538)
at kotlinx.serialization.internal.CollectionLikeSerializer.readElement(CollectionSerializers.kt:80)
at kotlinx.serialization.internal.AbstractCollectionSerializer.readElement$default(CollectionSerializers.kt:51)
at kotlinx.serialization.internal.AbstractCollectionSerializer.merge(CollectionSerializers.kt:36)
at nl.adaptivity.xmlutil.serialization.XmlDecoderBase$TagDecoderBase.decodeNullableSerializableElement(XMLDecoder.kt:976) |
@AdrienDaily That is a separate issue. Given your error it seems that for xml I need to add explicit support for a default serializer (I will explore how/why this can be done). At the same time, you can set the policy to have an unknownChildHandler that just ignores the tag. |
Ok thanks I will make a separate issue: #256 I have an unknownChildHandler but it doesn't change anything, I might be using it wrong. |
Hello,
Using the version 0.86.3
I'm having trouble getting from a children either an Element or a Text / CDATA result.
I'm not sure if it's the right way to handle it and I get this error:
Thanks a lot for your help
The text was updated successfully, but these errors were encountered: