Skip to content

Commit

Permalink
Fix caching to take descriptor hash code into account
Browse files Browse the repository at this point in the history
  • Loading branch information
pdvrieze committed Aug 9, 2024
1 parent 0373094 commit 6cfbf41
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 28 deletions.
2 changes: 2 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ Changes:
This aids #225.

Fixes:
- More reluctant caching of extended type descriptors such that type
parameters work correctly with caching.
- Fix NodeSerializer in the serialization module to properly forward
to the actual implementation.
- Don't make the companion of `XmlDeclMode` internal (#219). This is a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import kotlinx.serialization.descriptors.SerialKind
import kotlinx.serialization.descriptors.StructureKind
import nl.adaptivity.xmlutil.Namespace
import nl.adaptivity.xmlutil.QName
import nl.adaptivity.xmlutil.localPart
import nl.adaptivity.xmlutil.namespaceURI
import nl.adaptivity.xmlutil.serialization.XML.XmlCodecConfig
import nl.adaptivity.xmlutil.serialization.structure.SafeParentInfo
Expand All @@ -48,7 +47,7 @@ internal class DefaultFormatCache : FormatCache() {

@OptIn(ExperimentalSerializationApi::class)
override fun lookupType(namespace: Namespace?, serialDesc: SerialDescriptor, defaultValue: () -> XmlTypeDescriptor): XmlTypeDescriptor {
return lookupType(TypeKey(namespace?.namespaceURI, serialDesc.serialName), serialDesc.kind, defaultValue)
return lookupType(TypeKey(namespace?.namespaceURI, serialDesc.serialName, serialDesc.hashCode()), serialDesc.kind, defaultValue)
}

/**
Expand All @@ -57,12 +56,7 @@ internal class DefaultFormatCache : FormatCache() {
*/
@OptIn(ExperimentalSerializationApi::class)
override fun lookupType(parentName: QName, serialDesc: SerialDescriptor, defaultValue: () -> XmlTypeDescriptor): XmlTypeDescriptor {
return lookupType(TypeKey(parentName.namespaceURI, serialDesc.serialName), serialDesc.kind, defaultValue)
}

@OptIn(ExperimentalSerializationApi::class)
override fun lookupType(name: QName, kind: SerialKind, defaultValue: () -> XmlTypeDescriptor): XmlTypeDescriptor {
return lookupType(TypeKey(name.namespaceURI, name.localPart), kind, defaultValue)
return lookupType(TypeKey(parentName.namespaceURI, serialDesc.serialName, serialDesc.hashCode()), serialDesc.kind, defaultValue)
}

@OptIn(ExperimentalSerializationApi::class)
Expand Down Expand Up @@ -91,8 +85,6 @@ internal class DefaultFormatCache : FormatCache() {
// This has to be getOrPut rather than `computeIfAbsent` as computeIfAbsent prevents other
// changes to different types. GetOrPut does not have that property (but is technically slower)
return elemDescCache.getOrPut(key) {
// val parentName = serializerParent.descriptor?.typeDescriptor?.run { typeQname ?: serialName }
// println("Calculating new descriptor for $parentName/${serializerParent.elementSerialDescriptor.serialName}")
defaultValue()
}.also {
pendingDescs.remove(key)
Expand All @@ -106,9 +98,6 @@ internal class DefaultFormatCache : FormatCache() {
preserveSpace: Boolean
): XmlCompositeDescriptor {
return XmlCompositeDescriptor(codecConfig, serializerParent, tagParent, preserveSpace)
// return lookupDescriptor(null, serializerParent, tagParent, false) {
// XmlCompositeDescriptor(config, serializersModule, serializerParent, tagParent, preserveSpace)
// } as XmlCompositeDescriptor
}

internal data class DescKey(
Expand All @@ -118,11 +107,11 @@ internal class DefaultFormatCache : FormatCache() {
val canBeAttribute: Boolean
)

private data class TypeKey(val namespace: String, val serialName: String)
private data class TypeKey(val namespace: String, val serialName: String, val descriptorHash: Int)

companion object {
@JvmStatic
private fun TypeKey(namespace: String?, serialName: String) =
DefaultFormatCache.TypeKey(namespace ?: "", serialName)
private fun TypeKey(namespace: String?, serialName: String, descriptorHash: Int) =
DefaultFormatCache.TypeKey(namespace ?: "", serialName, descriptorHash)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,8 @@

package nl.adaptivity.xmlutil.serialization

import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.SerialKind
import nl.adaptivity.xmlutil.Namespace
import nl.adaptivity.xmlutil.QName
import nl.adaptivity.xmlutil.serialization.structure.SafeParentInfo
Expand All @@ -40,9 +38,6 @@ public abstract class FormatCache internal constructor(){
*/
internal abstract fun lookupType(parentName: QName, serialDesc: SerialDescriptor, defaultValue: () -> XmlTypeDescriptor): XmlTypeDescriptor

@OptIn(ExperimentalSerializationApi::class)
internal abstract fun lookupType(name: QName, kind: SerialKind, defaultValue: () -> XmlTypeDescriptor): XmlTypeDescriptor

internal abstract fun lookupDescriptor(
overridenSerializer: KSerializer<*>?,
serializerParent: SafeParentInfo,
Expand Down Expand Up @@ -71,13 +66,6 @@ public abstract class FormatCache internal constructor(){
defaultValue: () -> XmlTypeDescriptor
): XmlTypeDescriptor = defaultValue()

@OptIn(ExperimentalSerializationApi::class)
override fun lookupType(
name: QName,
kind: SerialKind,
defaultValue: () -> XmlTypeDescriptor
): XmlTypeDescriptor = defaultValue()

override fun lookupDescriptor(
overridenSerializer: KSerializer<*>?,
serializerParent: SafeParentInfo,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright (c) 2024.
*
* This file is part of xmlutil.
*
* This file is licenced to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You should have received a copy of the license with the source distribution.
* Alternatively, you may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package nl.adaptivity.xml.serialization.regressions

import io.github.pdvrieze.xmlutil.testutil.assertXmlEquals
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import nl.adaptivity.xmlutil.serialization.XML
import kotlin.test.Test
import kotlin.test.assertEquals

class TestCachedDescriptorCache {

@Test
fun testParameterisedSerializerCache() {
val format = XML {}

val serialized1 = format.encodeToString(Outer(Inner1(1, 2)))
assertXmlEquals("<Outer><Inner1 data1=\"1\" data2=\"2\"/></Outer>", serialized1)

val serialized2 = format.encodeToString(Outer(Inner2("a", "b", "c")))
assertXmlEquals("<Outer><Inner2 data3=\"a\" data4=\"b\" data5=\"c\"/></Outer>", serialized2)
}

@Serializable
data class Outer<T>(val data: T)

@Serializable
data class Inner1(val data1: Int, val data2: Int)

@Serializable
data class Inner2(val data3: String, val data4: String, val data5: String)
}

0 comments on commit 6cfbf41

Please sign in to comment.