Skip to content

Commit 5431f78

Browse files
committed
Fix review notes, tune initialCapacity in ConcurrentHashMap
1 parent 64a4e26 commit 5431f78

File tree

6 files changed

+33
-15
lines changed

6 files changed

+33
-15
lines changed

core/commonMain/src/kotlinx/serialization/Annotations.kt

+3
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,9 @@ public annotation class Serializer(
145145
* // Prints "{"int":42}"
146146
* println(Json.encodeToString(CustomName(42)))
147147
* ```
148+
*
149+
* If a name of class or property is overridden with this annotation, original source code name is not available for the library.
150+
* Tools like `JsonNamingStrategy` and `ProtoBufSchemaGenerator` would see and transform [value] from [SerialName] annotation.
148151
*/
149152
@Target(AnnotationTarget.PROPERTY, AnnotationTarget.CLASS)
150153
// @Retention(AnnotationRetention.RUNTIME) still runtime, but KT-41082

formats/json/commonMain/src/kotlinx/serialization/json/JsonNamingStrategy.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import kotlinx.serialization.descriptors.*
2626
* * Collision of the transformed name with any other (transformed) properties serial names or any alternative names
2727
* specified with [JsonNames] will lead to a deserialization exception.
2828
*
29-
* * Naming strategies do not transform serial names of the classes used for the polymorphism, as they always should be specified explicitly.
29+
* * Naming strategies do not transform serial names of the types used for the polymorphism, as they always should be specified explicitly.
3030
* Values from [JsonClassDiscriminator] or global [JsonBuilder.classDiscriminator] also are not altered.
3131
*
3232
* ### Controversy about using global naming strategies

formats/json/commonMain/src/kotlinx/serialization/json/internal/JsonNamesMap.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ internal fun SerialDescriptor.buildDeserializationNamesMap(json: Json): Map<Stri
2929
}
3030

3131
val builder: MutableMap<String, Int> =
32-
mutableMapOf() // can be not concurrent because it is only read after creation and never written to?
32+
mutableMapOf() // can be not concurrent because it is only read after creation and safely published to concurrent map
3333
val strategy = namingStrategy(json)
3434
for (i in 0 until elementsCount) {
3535
getElementAnnotations(i).filterIsInstance<JsonNames>().singleOrNull()?.names?.forEach { name ->

formats/json/commonMain/src/kotlinx/serialization/json/internal/SchemaCache.kt

+4-2
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@ private typealias DescriptorData<T> = MutableMap<DescriptorSchemaCache.Key<T>, T
1616
* To be able to work with it from multiple threads in Kotlin/Native, use @[ThreadLocal] in appropriate places.
1717
*/
1818
internal class DescriptorSchemaCache {
19-
private val map: MutableMap<SerialDescriptor, DescriptorData<Any>> = createMapForCache(1)
19+
// 16 is default CHM size, as we do not know number of descriptors in an application (but it's likely not 1)
20+
private val map: MutableMap<SerialDescriptor, DescriptorData<Any>> = createMapForCache(16)
2021

2122
@Suppress("UNCHECKED_CAST")
2223
public operator fun <T : Any> set(descriptor: SerialDescriptor, key: Key<T>, value: T) {
23-
map.getOrPut(descriptor, { createMapForCache(1) })[key as Key<Any>] = value as Any
24+
// Initial capacity = number of known DescriptorSchemaCache.Key instances
25+
map.getOrPut(descriptor, { createMapForCache(2) })[key as Key<Any>] = value as Any
2426
}
2527

2628
public fun <T : Any> getOrPut(descriptor: SerialDescriptor, key: Key<T>, defaultValue: () -> T): T {

formats/json/commonMain/src/kotlinx/serialization/json/internal/TreeJsonDecoder.kt

+15-8
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ private sealed class AbstractJsonTreeDecoder(
134134

135135
override fun decodeTaggedChar(tag: String): Char = getPrimitiveValue(tag).primitive("char") { content.single() }
136136

137-
private inline fun <T: Any> JsonPrimitive.primitive(primitive: String, block: JsonPrimitive.() -> T?): T {
137+
private inline fun <T : Any> JsonPrimitive.primitive(primitive: String, block: JsonPrimitive.() -> T?): T {
138138
try {
139139
return block() ?: unparsedPrimitive(primitive)
140140
} catch (e: IllegalArgumentException) {
@@ -236,9 +236,16 @@ private open class JsonTreeDecoder(
236236
}
237237
// Slow path
238238
val deserializationNamesMap = json.deserializationNamesMap(descriptor)
239-
val nameInObject = value.keys.find { deserializationNamesMap[it] == index }
240-
val fallbackName = strategy?.serialNameForJson(descriptor, index, descriptor.getElementName(index)) // Key not found exception should be thrown with transformed named, not original
241-
return nameInObject ?: fallbackName ?: baseName
239+
value.keys.find { deserializationNamesMap[it] == index }?.let {
240+
return it
241+
}
242+
243+
val fallbackName = strategy?.serialNameForJson(
244+
descriptor,
245+
index,
246+
baseName
247+
) // Key not found exception should be thrown with transformed name, not original
248+
return fallbackName ?: baseName
242249
}
243250

244251
override fun currentElement(tag: String): JsonElement = value.getValue(tag)
@@ -259,10 +266,10 @@ private open class JsonTreeDecoder(
259266

260267
@Suppress("DEPRECATION_ERROR")
261268
val names: Set<String> = when {
262-
strategy == null && !configuration.useAlternativeNames -> descriptor.jsonCachedSerialNames()
263-
strategy != null -> json.deserializationNamesMap(descriptor).keys
264-
else -> descriptor.jsonCachedSerialNames() + json.schemaCache[descriptor, JsonDeserializationNamesKey]?.keys.orEmpty()
265-
}
269+
strategy == null && !configuration.useAlternativeNames -> descriptor.jsonCachedSerialNames()
270+
strategy != null -> json.deserializationNamesMap(descriptor).keys
271+
else -> descriptor.jsonCachedSerialNames() + json.schemaCache[descriptor, JsonDeserializationNamesKey]?.keys.orEmpty()
272+
}
266273

267274
for (key in value.keys) {
268275
if (key !in names && key != polyDiscriminator) {

formats/json/jsMain/src/kotlinx/serialization/json/internal/DynamicDecoders.kt

+9-3
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,15 @@ private open class DynamicInput(
112112
}
113113
// Slow path
114114
val deserializationNamesMap = json.deserializationNamesMap(descriptor)
115-
val nameInObject = (keys as Array<String>).find { deserializationNamesMap[it] == index }
116-
val fallbackName = strategy?.serialNameForJson(descriptor, index, descriptor.getElementName(index)) // Key not found exception should be thrown with transformed name, not original
117-
return nameInObject ?: fallbackName ?: mainName
115+
(keys as Array<String>).find { deserializationNamesMap[it] == index }?.let {
116+
return it
117+
}
118+
val fallbackName = strategy?.serialNameForJson(
119+
descriptor,
120+
index,
121+
mainName
122+
) // Key not found exception should be thrown with transformed name, not original
123+
return fallbackName ?: mainName
118124
}
119125

120126
override fun decodeTaggedEnum(tag: String, enumDescriptor: SerialDescriptor): Int {

0 commit comments

Comments
 (0)