Skip to content

Commit c682e69

Browse files
authored
Merge pull request #220 from ProjectMapK/develop
Release 2024-02-10 16:25:16 +0000
2 parents b9c4b1f + 6cd18c0 commit c682e69

File tree

9 files changed

+67
-140
lines changed

9 files changed

+67
-140
lines changed

.github/workflows/lint-and-test-dev.yml

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ on:
2828
- "**.kt"
2929
- "**.java"
3030
- .github/workflows/lint-and-test-dev.yml
31+
32+
permissions:
33+
contents: write # for Dependency submission
34+
3135
jobs:
3236
lint-and-test-dev:
3337
name: lint-and-test-dev
@@ -39,20 +43,18 @@ jobs:
3943
- name: Checkout
4044
uses: actions/checkout@v4
4145
- name: Validate Gradle wrapper
42-
uses: gradle/wrapper-validation-action@v1
46+
uses: gradle/wrapper-validation-action@v2
4347
- name: Set up java
44-
uses: actions/setup-java@v3
48+
uses: actions/setup-java@v4
4549
with:
4650
java-version: '8'
4751
distribution: 'corretto'
48-
- name: Lint
49-
uses: gradle/gradle-build-action@v2
52+
- name: Setup Gradle
53+
uses: gradle/actions/setup-gradle@v3
5054
with:
51-
arguments: lintKotlin
55+
dependency-graph: generate-and-submit
56+
dependency-graph-continue-on-failure: false
57+
- name: Lint
58+
run: ./gradlew lintKotlin
5259
- name: Test
53-
uses: gradle/gradle-build-action@v2
54-
with:
55-
arguments: test
56-
# TODO: Prepare a separate WF to be executed only when there is a change in build.gradle.
57-
- name: Run snapshot action
58-
uses: mikepenz/[email protected]
60+
run: ./gradlew lintKotlin test

.github/workflows/release.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
name: release
12
on:
23
workflow_dispatch:
34
jobs:

.github/workflows/test-main.yml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,11 @@ jobs:
4747
- name: '1.9.21 K2'
4848
version: '1.9.21'
4949
k2: true
50-
- name: '2.0.0-Beta1'
51-
version: '2.0.0-Beta1'
50+
- name: '2.0.0-Beta3'
51+
version: '2.0.0-Beta3'
5252
k2: false
53-
- name: '2.0.0-Beta1 K2'
54-
version: '2.0.0-Beta1'
53+
- name: '2.0.0-Beta3 K2'
54+
version: '2.0.0-Beta3'
5555
k2: true
5656
env:
5757
KOTLIN_VERSION: ${{ matrix.kotlin.version }}
@@ -63,13 +63,13 @@ jobs:
6363
- name: Checkout
6464
uses: actions/checkout@v4
6565
- name: Validate Gradle wrapper
66-
uses: gradle/wrapper-validation-action@v1
66+
uses: gradle/wrapper-validation-action@v2
6767
- name: 'Set up java ${{ matrix.java-version }}'
68-
uses: actions/setup-java@v3
68+
uses: actions/setup-java@v4
6969
with:
7070
java-version: '${{ matrix.java-version }}'
7171
distribution: 'corretto'
72+
- name: Setup Gradle
73+
uses: gradle/actions/setup-gradle@v3
7274
- name: Test
73-
uses: gradle/gradle-build-action@v2
74-
with:
75-
arguments: test
75+
run: ./gradlew test

build.gradle.kts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ val jacksonVersion = libs.versions.jackson.get()
1616
val generatedSrcPath = "${layout.buildDirectory.get()}/generated/kotlin"
1717

1818
group = groupStr
19-
version = "${jacksonVersion}-beta10"
19+
version = "${jacksonVersion}-beta11"
2020

2121
repositories {
2222
mavenCentral()
@@ -98,6 +98,11 @@ public val kogeraVersion: Version = VersionUtil.parseVersion("$version", "$group
9898
into(file("$generatedSrcPath/${packageStr.replace(".", "/")}"))
9999
}
100100

101+
// Added to avoid failure in generating dependency graphs in CI.
102+
lintKotlinMain {
103+
dependsOn.add(generateKogeraVersion)
104+
}
105+
101106
compileKotlin {
102107
dependsOn.add(generateKogeraVersion)
103108
kotlinOptions.jvmTarget = "1.8"

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: 27 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +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

6+
import kotlinx.metadata.ClassKind
37
import kotlinx.metadata.ClassName
4-
import kotlinx.metadata.ExperimentalContextReceivers
5-
import kotlinx.metadata.Flags
6-
import kotlinx.metadata.KmClassExtensionVisitor
7-
import kotlinx.metadata.KmClassVisitor
8+
import kotlinx.metadata.KmClass
89
import kotlinx.metadata.KmConstructor
9-
import kotlinx.metadata.KmConstructorVisitor
10-
import kotlinx.metadata.KmExtensionType
1110
import kotlinx.metadata.KmFunction
12-
import kotlinx.metadata.KmFunctionVisitor
1311
import kotlinx.metadata.KmProperty
14-
import kotlinx.metadata.KmPropertyVisitor
1512
import kotlinx.metadata.KmType
16-
import kotlinx.metadata.KmTypeAliasVisitor
17-
import kotlinx.metadata.KmTypeParameterVisitor
18-
import kotlinx.metadata.KmTypeVisitor
19-
import kotlinx.metadata.KmVariance
20-
import kotlinx.metadata.KmVersionRequirementVisitor
21-
import kotlinx.metadata.flagsOf
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
29-
30-
// KmClassVisitor with all processing disabled as much as possible to reduce load
31-
internal sealed class ReducedKmClassVisitor : KmClassVisitor() {
32-
final override val delegate: KmClassVisitor? get() = null
33-
34-
// from KmDeclarationContainerVisitor
35-
override fun visitFunction(flags: Flags, name: String): KmFunctionVisitor? = null
36-
override fun visitProperty(
37-
flags: Flags,
38-
name: String,
39-
getterFlags: Flags,
40-
setterFlags: Flags
41-
): KmPropertyVisitor? = null
42-
override fun visitTypeAlias(flags: Flags, name: String): KmTypeAliasVisitor? = null
43-
override fun visitExtensions(type: KmExtensionType): KmClassExtensionVisitor? = null
44-
45-
// from KmClassVisitor
46-
override fun visit(flags: Flags, name: ClassName) {}
47-
override fun visitTypeParameter(
48-
flags: Flags,
49-
name: String,
50-
id: Int,
51-
variance: KmVariance
52-
): KmTypeParameterVisitor? = null
53-
override fun visitSupertype(flags: Flags): KmTypeVisitor? = null
54-
override fun visitConstructor(flags: Flags): KmConstructorVisitor? = null
55-
override fun visitCompanionObject(name: String) {}
56-
override fun visitNestedClass(name: String) {}
57-
override fun visitEnumEntry(name: String) {}
58-
override fun visitSealedSubclass(name: ClassName) {}
59-
override fun visitInlineClassUnderlyingPropertyName(name: String) {}
60-
override fun visitInlineClassUnderlyingType(flags: Flags): KmTypeVisitor? = null
61-
62-
@OptIn(ExperimentalContextReceivers::class)
63-
override fun visitContextReceiverType(flags: Flags): KmTypeVisitor? = null
64-
override fun visitVersionRequirement(): KmVersionRequirementVisitor? = null
65-
override fun visitEnd() {}
66-
}
18+
import kotlinx.metadata.internal.metadata.deserialization.Flags as ProtoFlags
6719

6820
// Jackson Metadata Class
6921
internal sealed interface JmClass {
7022
class CompanionObject(declaringClass: Class<*>, companionObject: String) {
71-
private class ReducedCompanionVisitor(companionClass: Class<*>) : ReducedKmClassVisitor() {
72-
val functions: MutableList<KmFunction> = arrayListOf()
73-
74-
init {
75-
companionClass.getAnnotation(Metadata::class.java)!!.accept(this)
76-
}
77-
78-
override fun visitFunction(flags: Flags, name: String): KmFunctionVisitor = KmFunction(flags, name)
79-
.apply { functions.add(this) }
80-
}
81-
8223
private val companionField: Field = declaringClass.getDeclaredField(companionObject)
8324
val type: Class<*> = companionField.type
8425
val isAccessible: Boolean = companionField.isAccessible
85-
private val functions by lazy { ReducedCompanionVisitor(type).functions }
26+
private val functions by lazy { type.toKmClass()!!.functions }
8627
val instance: Any by lazy {
8728
// To prevent the call from failing, save the initial value and then rewrite the flag.
8829
if (!companionField.isAccessible) companionField.isAccessible = true
@@ -95,7 +36,7 @@ internal sealed interface JmClass {
9536
}
9637
}
9738

98-
val flags: Flags
39+
val kind: ClassKind
9940
val constructors: List<KmConstructor>
10041
val sealedSubclasses: List<ClassName>
10142
val inlineClassUnderlyingType: KmType?
@@ -110,34 +51,35 @@ internal sealed interface JmClass {
11051

11152
private class JmClassImpl(
11253
clazz: Class<*>,
113-
metadata: Metadata,
54+
kmClass: KmClass,
11455
superJmClass: JmClass?,
11556
interfaceJmClasses: List<JmClass>
116-
) : ReducedKmClassVisitor(), JmClass {
117-
private val allPropsMap: MutableMap<String, KmProperty> = mutableMapOf()
57+
) : JmClass {
58+
private val allPropsMap: Map<String, KmProperty>
11859

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

122-
private var companionPropName: String? = null
123-
override var flags: Flags = flagsOf()
124-
override val constructors: MutableList<KmConstructor> = mutableListOf()
125-
override val sealedSubclasses: MutableList<ClassName> = mutableListOf()
126-
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
12768

12869
init {
129-
metadata.accept(this)
130-
13170
// Add properties of inherited classes and interfaces
13271
// If an `interface` is implicitly implemented by an abstract class,
13372
// it is necessary to obtain a more specific type, so always add it from the abstract class first.
134-
(superJmClass as JmClassImpl?)?.allPropsMap?.forEach {
135-
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+
}
13677
}
137-
@Suppress("UNCHECKED_CAST")
138-
(interfaceJmClasses as List<JmClassImpl>).forEach { i ->
139-
i.allPropsMap.forEach {
140-
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) }
14183
}
14284
}
14385

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

210125
internal fun JmClass(
211126
clazz: Class<*>,
212-
metadata: Metadata,
127+
kmClass: KmClass,
213128
superJmClass: JmClass?,
214129
interfaceJmClasses: List<JmClass>
215-
): 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
}

src/main/kotlin/io/github/projectmapk/jackson/module/kogera/deser/singletonSupport/KotlinBeanDeserializerModifier.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import com.fasterxml.jackson.databind.DeserializationConfig
55
import com.fasterxml.jackson.databind.JsonDeserializer
66
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier
77
import io.github.projectmapk.jackson.module.kogera.ReflectionCache
8-
import kotlinx.metadata.Flag
8+
import kotlinx.metadata.ClassKind
99
import java.io.Serializable
1010

1111
// [module-kotlin#225]: keep Kotlin singletons as singletons
@@ -19,10 +19,8 @@ internal class KotlinBeanDeserializerModifier(
1919
}
2020

2121
private fun objectSingletonInstance(beanClass: Class<*>): Any? = cache.getJmClass(beanClass)?.let {
22-
val flags = it.flags
23-
2422
// It is not assumed that the companion object is the target
25-
if (Flag.Class.IS_OBJECT(flags) && !Flag.Class.IS_COMPANION_OBJECT(flags)) {
23+
if (it.kind == ClassKind.OBJECT) {
2624
beanClass.getDeclaredField("INSTANCE").get(null)
2725
} else {
2826
null

0 commit comments

Comments
 (0)