From 7b6a371c5c22cbd0fafdf3a154afd43ad1bb7b6b Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sun, 10 Nov 2024 23:36:09 +0900 Subject: [PATCH 1/7] Porting #817 https://github.com/FasterXML/jackson-module-kotlin/pull/817 --- .../jackson/module/kogera/Extensions.kt | 2 +- .../kogera/zPorted/test/github/GitHub757.kt | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/test/kotlin/io/github/projectmapk/jackson/module/kogera/zPorted/test/github/GitHub757.kt diff --git a/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/Extensions.kt b/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/Extensions.kt index 2ddaab50..40dbb4a7 100644 --- a/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/Extensions.kt +++ b/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/Extensions.kt @@ -62,7 +62,7 @@ public inline fun ObjectMapper.readValue(src: ByteArray): T = readVa public inline fun ObjectMapper.treeToValue(n: TreeNode): T = readValue(this.treeAsTokens(n), jacksonTypeRef()) -public inline fun ObjectMapper.convertValue(from: Any): T = convertValue(from, jacksonTypeRef()) +public inline fun ObjectMapper.convertValue(from: Any?): T = convertValue(from, jacksonTypeRef()) public inline fun ObjectReader.readValueTyped(jp: JsonParser): T = readValue(jp, jacksonTypeRef()) public inline fun ObjectReader.readValuesTyped(jp: JsonParser): Iterator = diff --git a/src/test/kotlin/io/github/projectmapk/jackson/module/kogera/zPorted/test/github/GitHub757.kt b/src/test/kotlin/io/github/projectmapk/jackson/module/kogera/zPorted/test/github/GitHub757.kt new file mode 100644 index 00000000..a01f5ea8 --- /dev/null +++ b/src/test/kotlin/io/github/projectmapk/jackson/module/kogera/zPorted/test/github/GitHub757.kt @@ -0,0 +1,22 @@ +package io.github.projectmapk.jackson.module.kogera.zPorted.test.github + +import com.fasterxml.jackson.databind.json.JsonMapper +import io.github.projectmapk.jackson.module.kogera.KotlinFeature +import io.github.projectmapk.jackson.module.kogera.KotlinModule +import io.github.projectmapk.jackson.module.kogera.convertValue +import org.junit.jupiter.api.Assertions.assertNull +import org.junit.jupiter.api.Test + +class GitHub757 { + @Test + fun test() { + val kotlinModule = KotlinModule.Builder() + .enable(KotlinFeature.StrictNullChecks) + .build() + val mapper = JsonMapper.builder() + .addModule(kotlinModule) + .build() + val convertValue = mapper.convertValue(null) + assertNull(convertValue) + } +} From 61bca89c27e562f7a82e2464ef0184530829cc0f Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 16 Nov 2024 20:09:41 +0900 Subject: [PATCH 2/7] Remove unused --- .../KotlinPrimaryAnnotationIntrospector.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/annotationIntrospector/KotlinPrimaryAnnotationIntrospector.kt b/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/annotationIntrospector/KotlinPrimaryAnnotationIntrospector.kt index d263e4af..6434c3e0 100644 --- a/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/annotationIntrospector/KotlinPrimaryAnnotationIntrospector.kt +++ b/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/annotationIntrospector/KotlinPrimaryAnnotationIntrospector.kt @@ -20,7 +20,6 @@ import io.github.projectmapk.jackson.module.kogera.jmClass.JmProperty import io.github.projectmapk.jackson.module.kogera.jmClass.JmValueParameter import io.github.projectmapk.jackson.module.kogera.reconstructClass import io.github.projectmapk.jackson.module.kogera.toSignature -import kotlinx.metadata.KmClassifier import kotlinx.metadata.isNullable import java.lang.reflect.Constructor import java.lang.reflect.Executable @@ -140,8 +139,6 @@ private fun Constructor<*>.isPrimarilyConstructorOf(jmClass: JmClass): Boolean = ?.let { !it.isSecondary || jmClass.constructors.size == 1 } ?: false -private fun KmClassifier.isString(): Boolean = this is KmClassifier.Class && this.name == "kotlin/String" - private fun isPossibleSingleString( kotlinParams: List, javaFunction: Executable, From 609158a6d550891fc037f3e89b41c1f3e98dde1e Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 16 Nov 2024 20:11:10 +0900 Subject: [PATCH 3/7] Fix warn --- .../KotlinFallbackAnnotationIntrospector.kt | 2 +- .../KotlinPrimaryAnnotationIntrospector.kt | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/annotationIntrospector/KotlinFallbackAnnotationIntrospector.kt b/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/annotationIntrospector/KotlinFallbackAnnotationIntrospector.kt index 43c4a06e..e4e65b42 100644 --- a/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/annotationIntrospector/KotlinFallbackAnnotationIntrospector.kt +++ b/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/annotationIntrospector/KotlinFallbackAnnotationIntrospector.kt @@ -125,7 +125,7 @@ internal class KotlinFallbackAnnotationIntrospector( private fun JmValueParameter.isNullishTypeAt(index: Int): Boolean = arguments.getOrNull(index)?.let { // If it is not a StarProjection, type is not null it === KmTypeProjection.STAR || it.type!!.isNullable -} ?: true // If a type argument cannot be taken, treat it as nullable to avoid unexpected failure. +} != false // If a type argument cannot be taken, treat it as nullable to avoid unexpected failure. private fun JmValueParameter.requireStrictNullCheck(type: JavaType): Boolean = ((type.isArrayType || type.isCollectionLikeType) && !this.isNullishTypeAt(0)) || diff --git a/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/annotationIntrospector/KotlinPrimaryAnnotationIntrospector.kt b/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/annotationIntrospector/KotlinPrimaryAnnotationIntrospector.kt index 6434c3e0..9ecc9a31 100644 --- a/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/annotationIntrospector/KotlinPrimaryAnnotationIntrospector.kt +++ b/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/annotationIntrospector/KotlinPrimaryAnnotationIntrospector.kt @@ -136,8 +136,7 @@ internal class KotlinPrimaryAnnotationIntrospector( } private fun Constructor<*>.isPrimarilyConstructorOf(jmClass: JmClass): Boolean = jmClass.findJmConstructor(this) - ?.let { !it.isSecondary || jmClass.constructors.size == 1 } - ?: false + ?.let { !it.isSecondary || jmClass.constructors.size == 1 } == true private fun isPossibleSingleString( kotlinParams: List, From 4d2d547b8a569aa24b1a3e114990c7b110766d84 Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 23 Nov 2024 14:56:01 +0900 Subject: [PATCH 4/7] Update kogera version --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index a725d323..f15745da 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -16,7 +16,7 @@ val jacksonVersion = libs.versions.jackson.get() val generatedSrcPath = "${layout.buildDirectory.get()}/generated/kotlin" group = groupStr -version = "${jacksonVersion}-beta14" +version = "${jacksonVersion}-beta15" repositories { mavenCentral() From da5657d0ee5f68f7cc218c5d2ba673af5ad2d66d Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sun, 10 Nov 2024 23:00:14 +0900 Subject: [PATCH 5/7] Update Jackson --- README.md | 2 +- gradle/libs.versions.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b63ff580..358c5c16 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ This project makes several disruptive changes to achieve more `Kotlin-like` beha Details are summarized in [KogeraSpecificImplementations](./docs/KogeraSpecificImplementations.md). # Compatibility -- `jackson 2.17.x` +- `jackson 2.18.x` - `Java 8+` - `Kotlin 1.8.22+` diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 73e2b8ba..559eac57 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] kotlin = "1.8.22" # Mainly for CI, it can be rewritten by environment variable. -jackson = "2.17.3" +jackson = "2.18.1" # test libs junit = "5.11.3" From f0920c6c4684081c8fee7ba9ebb2415549c47aad Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sun, 24 Nov 2024 01:14:21 +0900 Subject: [PATCH 6/7] Migrated to implement findDefaultCreator --- .../KotlinFallbackAnnotationIntrospector.kt | 48 +++++++++++++++ .../KotlinPrimaryAnnotationIntrospector.kt | 58 ------------------- .../jackson/module/kogera/jmClass/JmClass.kt | 22 +------ .../module/kogera/jmClass/JmConstructor.kt | 20 +++++++ 4 files changed, 70 insertions(+), 78 deletions(-) diff --git a/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/annotationIntrospector/KotlinFallbackAnnotationIntrospector.kt b/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/annotationIntrospector/KotlinFallbackAnnotationIntrospector.kt index e4e65b42..9cd525e5 100644 --- a/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/annotationIntrospector/KotlinFallbackAnnotationIntrospector.kt +++ b/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/annotationIntrospector/KotlinFallbackAnnotationIntrospector.kt @@ -1,5 +1,6 @@ package io.github.projectmapk.jackson.module.kogera.annotationIntrospector +import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonSetter import com.fasterxml.jackson.annotation.Nulls import com.fasterxml.jackson.databind.JavaType @@ -11,11 +12,14 @@ import com.fasterxml.jackson.databind.introspect.AnnotatedMember import com.fasterxml.jackson.databind.introspect.AnnotatedMethod import com.fasterxml.jackson.databind.introspect.AnnotatedParameter import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector +import com.fasterxml.jackson.databind.introspect.PotentialCreator import com.fasterxml.jackson.databind.util.Converter import io.github.projectmapk.jackson.module.kogera.JSON_K_UNBOX_CLASS import io.github.projectmapk.jackson.module.kogera.KOTLIN_DURATION_CLASS import io.github.projectmapk.jackson.module.kogera.ReflectionCache import io.github.projectmapk.jackson.module.kogera.isUnboxableValueClass +import io.github.projectmapk.jackson.module.kogera.jmClass.JmClass +import io.github.projectmapk.jackson.module.kogera.jmClass.JmConstructor import io.github.projectmapk.jackson.module.kogera.jmClass.JmValueParameter import io.github.projectmapk.jackson.module.kogera.ser.KotlinDurationValueToJavaDurationConverter import io.github.projectmapk.jackson.module.kogera.ser.KotlinToJavaDurationConverter @@ -120,6 +124,38 @@ internal class KotlinFallbackAnnotationIntrospector( } } ?: super.findSetterInfo(ann) + + // If it is not a Kotlin class or an Enum, Creator is not used + private fun AnnotatedClass.creatableKotlinClass(): JmClass? = annotated + .takeIf { !it.isEnum } + ?.let { cache.getJmClass(it) } + + override fun findDefaultCreator( + config: MapperConfig<*>, + valueClass: AnnotatedClass, + declaredConstructors: List, + declaredFactories: List + ): PotentialCreator? { + val jmClass = valueClass.creatableKotlinClass() ?: return null + val primarilyConstructor = jmClass.primarilyConstructor() + ?.takeIf { it.valueParameters.isNotEmpty() } + ?: return null + val isPossiblySingleString = isPossiblySingleString(primarilyConstructor, jmClass) + + for (it in declaredConstructors) { + val javaConstructor = it.creator().annotated as Constructor<*> + + if (primarilyConstructor.isMetadataFor(javaConstructor)) { + if (isPossibleSingleString(isPossiblySingleString, javaConstructor)) { + break + } else { + return it + } + } + } + + return null + } } private fun JmValueParameter.isNullishTypeAt(index: Int): Boolean = arguments.getOrNull(index)?.let { @@ -130,3 +166,15 @@ private fun JmValueParameter.isNullishTypeAt(index: Int): Boolean = arguments.ge private fun JmValueParameter.requireStrictNullCheck(type: JavaType): Boolean = ((type.isArrayType || type.isCollectionLikeType) && !this.isNullishTypeAt(0)) || (type.isMapLikeType && !this.isNullishTypeAt(1)) + +private fun JmClass.primarilyConstructor() = constructors.find { !it.isSecondary } ?: constructors.singleOrNull() + +private fun isPossiblySingleString( + jmConstructor: JmConstructor, + jmClass: JmClass +) = jmConstructor.valueParameters.singleOrNull()?.let { it.isString && it.name !in jmClass.propertyNameSet } == true + +private fun isPossibleSingleString( + isPossiblySingleString: Boolean, + javaConstructor: Constructor<*> +): Boolean = isPossiblySingleString && javaConstructor.parameters[0].annotations.none { it is JsonProperty } diff --git a/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/annotationIntrospector/KotlinPrimaryAnnotationIntrospector.kt b/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/annotationIntrospector/KotlinPrimaryAnnotationIntrospector.kt index 9ecc9a31..5c2cb363 100644 --- a/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/annotationIntrospector/KotlinPrimaryAnnotationIntrospector.kt +++ b/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/annotationIntrospector/KotlinPrimaryAnnotationIntrospector.kt @@ -1,11 +1,7 @@ package io.github.projectmapk.jackson.module.kogera.annotationIntrospector -import com.fasterxml.jackson.annotation.JsonCreator -import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.databind.JavaType -import com.fasterxml.jackson.databind.cfg.MapperConfig import com.fasterxml.jackson.databind.introspect.Annotated -import com.fasterxml.jackson.databind.introspect.AnnotatedConstructor import com.fasterxml.jackson.databind.introspect.AnnotatedField import com.fasterxml.jackson.databind.introspect.AnnotatedMember import com.fasterxml.jackson.databind.introspect.AnnotatedMethod @@ -14,17 +10,13 @@ import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector import com.fasterxml.jackson.databind.jsontype.NamedType import io.github.projectmapk.jackson.module.kogera.JSON_PROPERTY_CLASS import io.github.projectmapk.jackson.module.kogera.ReflectionCache -import io.github.projectmapk.jackson.module.kogera.hasCreatorAnnotation import io.github.projectmapk.jackson.module.kogera.jmClass.JmClass import io.github.projectmapk.jackson.module.kogera.jmClass.JmProperty -import io.github.projectmapk.jackson.module.kogera.jmClass.JmValueParameter import io.github.projectmapk.jackson.module.kogera.reconstructClass import io.github.projectmapk.jackson.module.kogera.toSignature import kotlinx.metadata.isNullable import java.lang.reflect.Constructor -import java.lang.reflect.Executable import java.lang.reflect.Method -import java.lang.reflect.Modifier // AnnotationIntrospector that overrides the behavior of the default AnnotationIntrospector // (in most cases, JacksonAnnotationIntrospector). @@ -115,54 +107,4 @@ internal class KotlinPrimaryAnnotationIntrospector( override fun findSubtypes(a: Annotated): List? = cache.getJmClass(a.rawType)?.let { jmClass -> jmClass.sealedSubclasses.map { NamedType(it.reconstructClass()) }.ifEmpty { null } } - - // Return Mode.DEFAULT if ann is a Primary Constructor and the condition is satisfied. - // Currently, there is no way to define the priority of a Creator, - // so the presence or absence of a JsonCreator is included in the decision. - // The reason for overriding the JacksonAnnotationIntrospector is to reduce overhead. - // In rare cases, a problem may occur, - // but it is assumed that the problem can be solved by adjusting the order of module registration. - override fun findCreatorAnnotation(config: MapperConfig<*>, ann: Annotated): JsonCreator.Mode? { - (ann as? AnnotatedConstructor)?.takeIf { 0 < it.parameterCount } ?: return null - - val declaringClass = ann.declaringClass - val jmClass = declaringClass.takeIf { !it.isEnum } - ?.let { cache.getJmClass(it) } - ?: return null - - return JsonCreator.Mode.DEFAULT - .takeIf { ann.annotated.isPrimarilyConstructorOf(jmClass) && !hasCreator(declaringClass, jmClass) } - } -} - -private fun Constructor<*>.isPrimarilyConstructorOf(jmClass: JmClass): Boolean = jmClass.findJmConstructor(this) - ?.let { !it.isSecondary || jmClass.constructors.size == 1 } == true - -private fun isPossibleSingleString( - kotlinParams: List, - javaFunction: Executable, - propertyNames: Set -): Boolean = kotlinParams.size == 1 && - kotlinParams[0].let { it.name !in propertyNames && it.isString } && - javaFunction.parameters[0].annotations.none { it is JsonProperty } - -private fun hasCreatorConstructor(clazz: Class<*>, jmClass: JmClass, propertyNames: Set): Boolean { - val kmConstructorMap = jmClass.constructors.associateBy { it.signature?.descriptor } - - return clazz.constructors.any { constructor -> - val kmConstructor = kmConstructorMap[constructor.toSignature().descriptor] ?: return@any false - - !isPossibleSingleString(kmConstructor.valueParameters, constructor, propertyNames) && - constructor.hasCreatorAnnotation() - } -} - -// In the original, `isPossibleSingleString` comparison was disabled, -// and if enabled, the behavior would have changed, so the comparison is skipped. -private fun hasCreatorFunction(clazz: Class<*>): Boolean = clazz.declaredMethods - .any { Modifier.isStatic(it.modifiers) && it.hasCreatorAnnotation() } - -private fun hasCreator(clazz: Class<*>, jmClass: JmClass): Boolean { - val propertyNames = jmClass.propertyNameSet - return hasCreatorConstructor(clazz, jmClass, propertyNames) || hasCreatorFunction(clazz) } diff --git a/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/jmClass/JmClass.kt b/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/jmClass/JmClass.kt index 2d72ae9d..f390c683 100644 --- a/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/jmClass/JmClass.kt +++ b/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/jmClass/JmClass.kt @@ -1,7 +1,6 @@ package io.github.projectmapk.jackson.module.kogera.jmClass import io.github.projectmapk.jackson.module.kogera.reconstructClassOrNull -import io.github.projectmapk.jackson.module.kogera.toDescBuilder import io.github.projectmapk.jackson.module.kogera.toKmClass import io.github.projectmapk.jackson.module.kogera.toSignature import kotlinx.metadata.ClassKind @@ -106,25 +105,8 @@ private class JmClassImpl( companionPropName?.let { JmClass.CompanionObject(clazz, it) } } - override fun findJmConstructor(constructor: Constructor<*>): JmConstructor? { - val descHead = constructor.parameterTypes.toDescBuilder() - val len = descHead.length - val desc = CharArray(len + 1).apply { - descHead.getChars(0, len, this, 0) - this[len] = 'V' - }.let { String(it) } - - // Only constructors that take a value class as an argument have a DefaultConstructorMarker on the Signature. - val valueDesc = descHead - .replace(len - 1, len, "Lkotlin/jvm/internal/DefaultConstructorMarker;)V") - .toString() - - // Constructors always have the same name, so only desc is compared - return constructors.find { - val targetDesc = it.signature?.descriptor - targetDesc == desc || targetDesc == valueDesc - } - } + override fun findJmConstructor(constructor: Constructor<*>): JmConstructor? = + constructors.find { it.isMetadataFor(constructor) } // Field name always matches property name override fun findPropertyByField(field: Field): JmProperty? = allPropsMap[field.name] diff --git a/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/jmClass/JmConstructor.kt b/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/jmClass/JmConstructor.kt index 67340239..e2311f33 100644 --- a/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/jmClass/JmConstructor.kt +++ b/src/main/kotlin/io/github/projectmapk/jackson/module/kogera/jmClass/JmConstructor.kt @@ -1,9 +1,11 @@ package io.github.projectmapk.jackson.module.kogera.jmClass +import io.github.projectmapk.jackson.module.kogera.toDescBuilder import kotlinx.metadata.KmConstructor import kotlinx.metadata.isSecondary import kotlinx.metadata.jvm.JvmMethodSignature import kotlinx.metadata.jvm.signature +import java.lang.reflect.Constructor internal data class JmConstructor( val isSecondary: Boolean, @@ -15,4 +17,22 @@ internal data class JmConstructor( signature = constructor.signature, valueParameters = constructor.valueParameters.map { JmValueParameter(it) } ) + + // Only constructors that take a value class as an argument have a DefaultConstructorMarker on the Signature. + private fun StringBuilder.valueDesc(len: Int) = + replace(len - 1, len, "Lkotlin/jvm/internal/DefaultConstructorMarker;)V").toString() + + fun isMetadataFor(constructor: Constructor<*>): Boolean { + val targetDesc = signature?.descriptor + + val descHead = constructor.parameterTypes.toDescBuilder() + val len = descHead.length + val desc = CharArray(len + 1).apply { + descHead.getChars(0, len, this, 0) + this[len] = 'V' + }.let { String(it) } + + // Constructors always have the same name, so only desc is compared + return targetDesc == desc || targetDesc == descHead.valueDesc(len) + } } From e116b4f806d45291c43ca2983c750c6726e5091b Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sun, 24 Nov 2024 01:24:41 +0900 Subject: [PATCH 7/7] Porting check for #844 from https://github.com/FasterXML/jackson-module-kotlin/pull/855 --- .../kogera/zPorted/test/github/GitHub844.kt | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/test/kotlin/io/github/projectmapk/jackson/module/kogera/zPorted/test/github/GitHub844.kt diff --git a/src/test/kotlin/io/github/projectmapk/jackson/module/kogera/zPorted/test/github/GitHub844.kt b/src/test/kotlin/io/github/projectmapk/jackson/module/kogera/zPorted/test/github/GitHub844.kt new file mode 100644 index 00000000..3ac6609f --- /dev/null +++ b/src/test/kotlin/io/github/projectmapk/jackson/module/kogera/zPorted/test/github/GitHub844.kt @@ -0,0 +1,30 @@ +package io.github.projectmapk.jackson.module.kogera.zPorted.test.github + +import com.fasterxml.jackson.annotation.JsonTypeInfo +import com.fasterxml.jackson.databind.ObjectMapper +import io.github.projectmapk.jackson.module.kogera.readValue +import io.github.projectmapk.jackson.module.kogera.registerKotlinModule +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test + +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "_type") +private sealed class BaseClass + +private data class ChildClass(val text: String) : BaseClass() + +class GitHub844 { + @Test + fun test() { + val json = """ + { + "_type": "ChildClass", + "text": "Test" + } + """ + + val jacksonObjectMapper = ObjectMapper().registerKotlinModule() + val message = jacksonObjectMapper.readValue(json) + + assertEquals(ChildClass("Test"), message) + } +}