Skip to content

Commit 5ce8368

Browse files
authored
Merge pull request #218 from ProjectMapK/update-kogera
Update `kotlinx-metadata-jvm`
2 parents e01e3de + f1c4186 commit 5ce8368

File tree

4 files changed

+33
-113
lines changed

4 files changed

+33
-113
lines changed

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ junit = "5.10.1"
77

88
[libraries]
99
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib" }
10-
kotlinx-metadata-jvm = "org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.7.0"
10+
kotlinx-metadata-jvm = "org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.9.0"
1111
jackson-databind = { module = "com.fasterxml.jackson.core:jackson-databind", version.ref = "jackson" }
1212
jackson-annotations = { module = "com.fasterxml.jackson.core:jackson-annotations", version.ref = "jackson" }
1313

src/main/kotlin/io/github/projectmapk/jackson/module/kogera/InternalCommons.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,23 @@
11
package io.github.projectmapk.jackson.module.kogera
22

33
import com.fasterxml.jackson.annotation.JsonCreator
4+
import kotlinx.metadata.KmClass
45
import kotlinx.metadata.KmClassifier
56
import kotlinx.metadata.KmType
67
import kotlinx.metadata.isNullable
78
import kotlinx.metadata.jvm.JvmMethodSignature
9+
import kotlinx.metadata.jvm.KotlinClassMetadata
810
import java.lang.reflect.AnnotatedElement
911
import java.lang.reflect.Constructor
1012
import java.lang.reflect.Method
1113

1214
internal typealias JavaDuration = java.time.Duration
1315
internal typealias KotlinDuration = kotlin.time.Duration
1416

17+
internal fun Class<*>.toKmClass(): KmClass? = getAnnotation(Metadata::class.java)?.let {
18+
(KotlinClassMetadata.readStrict(it) as KotlinClassMetadata.Class).kmClass
19+
}
20+
1521
internal fun Class<*>.isUnboxableValueClass() = this.isAnnotationPresent(JvmInline::class.java)
1622

1723
// JmClass must be value class.
Lines changed: 24 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,29 @@
1+
// Visitor API has already been deprecated, but the error is being suppressed for now.
2+
@file:Suppress("DEPRECATION_ERROR")
3+
14
package io.github.projectmapk.jackson.module.kogera
25

36
import kotlinx.metadata.ClassKind
47
import kotlinx.metadata.ClassName
5-
import kotlinx.metadata.ExperimentalContextReceivers
6-
import kotlinx.metadata.Flags
7-
import kotlinx.metadata.KmClassExtensionVisitor
8-
import kotlinx.metadata.KmClassVisitor
8+
import kotlinx.metadata.KmClass
99
import kotlinx.metadata.KmConstructor
10-
import kotlinx.metadata.KmConstructorVisitor
11-
import kotlinx.metadata.KmExtensionType
1210
import kotlinx.metadata.KmFunction
13-
import kotlinx.metadata.KmFunctionVisitor
1411
import kotlinx.metadata.KmProperty
15-
import kotlinx.metadata.KmPropertyVisitor
1612
import kotlinx.metadata.KmType
17-
import kotlinx.metadata.KmTypeAliasVisitor
18-
import kotlinx.metadata.KmTypeParameterVisitor
19-
import kotlinx.metadata.KmTypeVisitor
20-
import kotlinx.metadata.KmVariance
21-
import kotlinx.metadata.KmVersionRequirementVisitor
22-
import kotlinx.metadata.internal.accept
23-
import kotlinx.metadata.internal.metadata.jvm.deserialization.JvmProtoBufUtil
2413
import kotlinx.metadata.jvm.getterSignature
2514
import kotlinx.metadata.jvm.signature
2615
import java.lang.reflect.Constructor
2716
import java.lang.reflect.Field
2817
import java.lang.reflect.Method
2918
import kotlinx.metadata.internal.metadata.deserialization.Flags as ProtoFlags
3019

31-
// KmClassVisitor with all processing disabled as much as possible to reduce load
32-
internal sealed class ReducedKmClassVisitor : KmClassVisitor() {
33-
final override val delegate: KmClassVisitor? get() = null
34-
35-
// from KmDeclarationContainerVisitor
36-
override fun visitFunction(flags: Flags, name: String): KmFunctionVisitor? = null
37-
override fun visitProperty(
38-
flags: Flags,
39-
name: String,
40-
getterFlags: Flags,
41-
setterFlags: Flags
42-
): KmPropertyVisitor? = null
43-
override fun visitTypeAlias(flags: Flags, name: String): KmTypeAliasVisitor? = null
44-
override fun visitExtensions(type: KmExtensionType): KmClassExtensionVisitor? = null
45-
46-
// from KmClassVisitor
47-
override fun visit(flags: Flags, name: ClassName) {}
48-
override fun visitTypeParameter(
49-
flags: Flags,
50-
name: String,
51-
id: Int,
52-
variance: KmVariance
53-
): KmTypeParameterVisitor? = null
54-
override fun visitSupertype(flags: Flags): KmTypeVisitor? = null
55-
override fun visitConstructor(flags: Flags): KmConstructorVisitor? = null
56-
override fun visitCompanionObject(name: String) {}
57-
override fun visitNestedClass(name: String) {}
58-
override fun visitEnumEntry(name: String) {}
59-
override fun visitSealedSubclass(name: ClassName) {}
60-
override fun visitInlineClassUnderlyingPropertyName(name: String) {}
61-
override fun visitInlineClassUnderlyingType(flags: Flags): KmTypeVisitor? = null
62-
63-
@OptIn(ExperimentalContextReceivers::class)
64-
override fun visitContextReceiverType(flags: Flags): KmTypeVisitor? = null
65-
override fun visitVersionRequirement(): KmVersionRequirementVisitor? = null
66-
override fun visitEnd() {}
67-
}
68-
6920
// Jackson Metadata Class
7021
internal sealed interface JmClass {
7122
class CompanionObject(declaringClass: Class<*>, companionObject: String) {
72-
private class ReducedCompanionVisitor(companionClass: Class<*>) : ReducedKmClassVisitor() {
73-
val functions: MutableList<KmFunction> = arrayListOf()
74-
75-
init {
76-
companionClass.getAnnotation(Metadata::class.java)!!.accept(this)
77-
}
78-
79-
override fun visitFunction(flags: Flags, name: String): KmFunctionVisitor = KmFunction(flags, name)
80-
.apply { functions.add(this) }
81-
}
82-
8323
private val companionField: Field = declaringClass.getDeclaredField(companionObject)
8424
val type: Class<*> = companionField.type
8525
val isAccessible: Boolean = companionField.isAccessible
86-
private val functions by lazy { ReducedCompanionVisitor(type).functions }
26+
private val functions by lazy { type.toKmClass()!!.functions }
8727
val instance: Any by lazy {
8828
// To prevent the call from failing, save the initial value and then rewrite the flag.
8929
if (!companionField.isAccessible) companionField.isAccessible = true
@@ -111,34 +51,35 @@ internal sealed interface JmClass {
11151

11252
private class JmClassImpl(
11353
clazz: Class<*>,
114-
metadata: Metadata,
54+
kmClass: KmClass,
11555
superJmClass: JmClass?,
11656
interfaceJmClasses: List<JmClass>
117-
) : ReducedKmClassVisitor(), JmClass {
118-
private val allPropsMap: MutableMap<String, KmProperty> = mutableMapOf()
57+
) : JmClass {
58+
private val allPropsMap: Map<String, KmProperty>
11959

12060
// Defined as non-lazy because it is always read in both serialization and deserialization
12161
override val properties: List<KmProperty>
12262

123-
private var companionPropName: String? = null
124-
override lateinit var kind: ClassKind
125-
override val constructors: MutableList<KmConstructor> = mutableListOf()
126-
override val sealedSubclasses: MutableList<ClassName> = mutableListOf()
127-
override var inlineClassUnderlyingType: KmType? = null
63+
private val companionPropName: String? = kmClass.companionObject
64+
override val kind: ClassKind = ClassKind.values()[ProtoFlags.CLASS_KIND.get(kmClass.flags).number]
65+
override val constructors: List<KmConstructor> = kmClass.constructors
66+
override val sealedSubclasses: List<ClassName> = kmClass.sealedSubclasses
67+
override val inlineClassUnderlyingType: KmType? = kmClass.inlineClassUnderlyingType
12868

12969
init {
130-
metadata.accept(this)
131-
13270
// Add properties of inherited classes and interfaces
13371
// If an `interface` is implicitly implemented by an abstract class,
13472
// it is necessary to obtain a more specific type, so always add it from the abstract class first.
135-
(superJmClass as JmClassImpl?)?.allPropsMap?.forEach {
136-
this.allPropsMap.putIfAbsent(it.key, it.value)
73+
val tempPropsMap = ((superJmClass as JmClassImpl?)?.allPropsMap?.toMutableMap() ?: mutableMapOf()).apply {
74+
kmClass.properties.forEach {
75+
this[it.name] = it
76+
}
13777
}
138-
@Suppress("UNCHECKED_CAST")
139-
(interfaceJmClasses as List<JmClassImpl>).forEach { i ->
140-
i.allPropsMap.forEach {
141-
this.allPropsMap.putIfAbsent(it.key, it.value)
78+
79+
allPropsMap = interfaceJmClasses.fold(tempPropsMap) { acc, cur ->
80+
val curProps = (cur as JmClassImpl).allPropsMap
81+
acc.apply {
82+
curProps.forEach { acc.putIfAbsent(it.key, it.value) }
14283
}
14384
}
14485

@@ -179,38 +120,11 @@ private class JmClassImpl(
179120
val getterName = getter.name
180121
return properties.find { it.getterSignature?.name == getterName }
181122
}
182-
183-
// KmClassVisitor
184-
override fun visit(flags: Flags, name: ClassName) {
185-
kind = ClassKind.values()[ProtoFlags.CLASS_KIND.get(flags).number]
186-
}
187-
188-
override fun visitProperty(flags: Flags, name: String, getterFlags: Flags, setterFlags: Flags): KmPropertyVisitor =
189-
KmProperty(flags, name, getterFlags, setterFlags).apply { allPropsMap[name] = this }
190-
191-
override fun visitConstructor(flags: Flags): KmConstructorVisitor =
192-
KmConstructor(flags).apply { constructors.add(this) }
193-
194-
override fun visitCompanionObject(name: String) {
195-
this.companionPropName = name
196-
}
197-
198-
override fun visitSealedSubclass(name: ClassName) {
199-
sealedSubclasses.add(name)
200-
}
201-
202-
override fun visitInlineClassUnderlyingType(flags: Flags): KmTypeVisitor =
203-
KmType(flags).also { inlineClassUnderlyingType = it }
204-
}
205-
206-
private fun Metadata.accept(visitor: ReducedKmClassVisitor) {
207-
val (strings, proto) = JvmProtoBufUtil.readClassDataFrom(data1.takeIf(Array<*>::isNotEmpty)!!, data2)
208-
proto.accept(visitor, strings)
209123
}
210124

211125
internal fun JmClass(
212126
clazz: Class<*>,
213-
metadata: Metadata,
127+
kmClass: KmClass,
214128
superJmClass: JmClass?,
215129
interfaceJmClasses: List<JmClass>
216-
): JmClass = JmClassImpl(clazz, metadata, superJmClass, interfaceJmClasses)
130+
): JmClass = JmClassImpl(clazz, kmClass, superJmClass, interfaceJmClasses)

src/main/kotlin/io/github/projectmapk/jackson/module/kogera/ReflectionCache.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ internal class ReflectionCache(initialCacheSize: Int, maxCacheSize: Int) : Seria
4848

4949
fun getJmClass(clazz: Class<*>): JmClass? {
5050
return find(clazz) ?: run {
51-
val metadata = clazz.getAnnotation(Metadata::class.java) ?: return null
51+
val kmClass = clazz.toKmClass() ?: return null
5252

5353
// Do not parse super class for interfaces.
5454
val superJmClass = if (!clazz.isInterface) {
@@ -61,7 +61,7 @@ internal class ReflectionCache(initialCacheSize: Int, maxCacheSize: Int) : Seria
6161
}
6262
val interfaceJmClasses = clazz.interfaces.mapNotNull { getJmClass(it) }
6363

64-
val value = JmClass(clazz, metadata, superJmClass, interfaceJmClasses)
64+
val value = JmClass(clazz, kmClass, superJmClass, interfaceJmClasses)
6565
putIfAbsent(clazz, value)
6666
}
6767
}

0 commit comments

Comments
 (0)