From b16059c02e249c3a3a233edab282ddeabb15d100 Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Tue, 25 May 2021 23:22:06 +0900 Subject: [PATCH 1/8] add test cases --- .../module/kotlin/test/github/Github356.kt | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/github/Github356.kt b/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/github/Github356.kt index d77072e89..821081825 100644 --- a/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/github/Github356.kt +++ b/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/github/Github356.kt @@ -21,6 +21,30 @@ class TestGithub356 { assertEquals("""{"inlineClassProperty":"bar"}""", mapper.writeValueAsString(original)) } + @Test + fun deserializeKebabInlineMember() { + val original = ClassWithKebabInlineMember(ValueClass("bar")) + assertEquals(original, mapper.readValue(mapper.writeValueAsString(original))) + } + + @Test + fun serializeKebabInlineClass() { + val original = ClassWithKebabInlineMember(ValueClass("bar")) + assertEquals("""{"value-class-property":"bar"}""", mapper.writeValueAsString(original)) + } + + @Test + fun deserializeNamedInlineClass() { + val original = ClassWithNamedInlineMember(ValueClass("bar")) + assertEquals(original, mapper.readValue(mapper.writeValueAsString(original))) + } + + @Test + fun serializeNamedInlineClass() { + val original = ClassWithNamedInlineMember(ValueClass("bar")) + assertEquals("""{"value-":"bar"}""", mapper.writeValueAsString(original)) + } + @Test fun deserializeValueClass() { val original = ClassWithValueMember(ValueClass("bar")) @@ -54,3 +78,17 @@ data class ClassWithValueMember(val valueClassProperty: ValueClass) { fun build() = ClassWithValueMember(ValueClass(valueClassProperty)) } } + +@JsonDeserialize(builder = ClassWithKebabInlineMember.JacksonBuilder::class) +data class ClassWithKebabInlineMember(val `value-class-property`: ValueClass) { + data class JacksonBuilder constructor(val `value-class-property`: String) { + fun build() = ClassWithKebabInlineMember(ValueClass(`value-class-property`)) + } +} + +@JsonDeserialize(builder = ClassWithNamedInlineMember.JacksonBuilder::class) +data class ClassWithNamedInlineMember(@get:JvmName("getValue-") val `value-`: ValueClass) { + data class JacksonBuilder constructor(val `value-`: String) { + fun build() = ClassWithNamedInlineMember(ValueClass(`value-`)) + } +} From 858e0c20a31e56f4ddcf04265b07b3241b7f1064 Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Tue, 25 May 2021 23:26:02 +0900 Subject: [PATCH 2/8] fix issue --- .../KotlinNamesAnnotationIntrospector.kt | 54 ++++++++++--------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt index e71d5e099..d4facc5cb 100644 --- a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt +++ b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt @@ -18,38 +18,42 @@ import java.util.Locale import kotlin.reflect.KClass import kotlin.reflect.KFunction import kotlin.reflect.KParameter -import kotlin.reflect.full.companionObject -import kotlin.reflect.full.declaredFunctions -import kotlin.reflect.full.memberProperties -import kotlin.reflect.full.primaryConstructor +import kotlin.reflect.full.* import kotlin.reflect.jvm.internal.KotlinReflectionInternalError +import kotlin.reflect.jvm.javaGetter import kotlin.reflect.jvm.javaType import kotlin.reflect.jvm.kotlinFunction internal class KotlinNamesAnnotationIntrospector(val module: KotlinModule, val cache: ReflectionCache, val ignoredClassesForImplyingJsonCreator: Set>) : NopAnnotationIntrospector() { // since 2.4 - override fun findImplicitPropertyName(member: AnnotatedMember): String? { - if (member is AnnotatedMethod && member.isInlineClass()) { - if (member.name.startsWith("get") && - member.name.contains('-') && - member.parameterCount == 0) { - return member.name.substringAfter("get") - .replaceFirstChar { it.lowercase(Locale.getDefault()) } - .substringBefore('-') - } else if (member.name.startsWith("is") && - member.name.contains('-') && - member.parameterCount == 0) { - return member.name.substringAfter("is") - .replaceFirstChar { it.lowercase(Locale.getDefault()) } - .substringBefore('-') - } - } else if (member is AnnotatedParameter) { - return findKotlinParameterName(member) - } - - return null + override fun findImplicitPropertyName(member: AnnotatedMember): String? = when (member) { + is AnnotatedMethod -> findImplicitPropertyNameFromKotlinPropertyIfNeeded(member) + is AnnotatedParameter -> findKotlinParameterName(member) + else -> null } + // Since getter for value class (inline class) will be compiled into a different name such as "getFoo-${random}", + // use the property name in Kotlin in such a case. + private fun findImplicitPropertyNameFromKotlinPropertyIfNeeded(member: AnnotatedMethod): String? = member + .takeIf { + it.parameterCount == 0 && + it.name.run { contains("-") && (startsWith("get") || startsWith("is")) } + }?.let { _ -> + val propertyNameFromGetter = member.name.let { + when { + it.startsWith("get") -> it.substringAfter("get") + it.startsWith("is") -> it.substringAfter("is") + else -> throw IllegalStateException("Should not get here.") + } + }.replaceFirstChar { it.lowercase(Locale.getDefault()) } + + member.declaringClass.kotlin.declaredMemberProperties.find { kProperty1 -> + kProperty1.javaGetter + ?.let { it == member.member && kProperty1.name != propertyNameFromGetter } + ?: false + }?.name + } + // since 2.11: support Kotlin's way of handling "isXxx" backed properties where // logical property name needs to remain "isXxx" and not become "xxx" as with Java Beans // (see https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html and @@ -169,5 +173,3 @@ internal class KotlinNamesAnnotationIntrospector(val module: KotlinModule, val c } } } - -private fun AnnotatedMethod.isInlineClass() = declaringClass.declaredMethods.any { it.name.contains('-') } From b67bb9a46e0be657fc08b634bd44302bfc321c97 Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Fri, 28 May 2021 04:22:27 +0900 Subject: [PATCH 3/8] separation --- .../kotlin/KotlinNamesAnnotationIntrospector.kt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt index d4facc5cb..8d078fef9 100644 --- a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt +++ b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt @@ -32,13 +32,10 @@ internal class KotlinNamesAnnotationIntrospector(val module: KotlinModule, val c else -> null } - // Since getter for value class (inline class) will be compiled into a different name such as "getFoo-${random}", - // use the property name in Kotlin in such a case. + // Use Kotlin property names as needed. private fun findImplicitPropertyNameFromKotlinPropertyIfNeeded(member: AnnotatedMethod): String? = member - .takeIf { - it.parameterCount == 0 && - it.name.run { contains("-") && (startsWith("get") || startsWith("is")) } - }?.let { _ -> + .takeIf { it.parameterCount == 0 && looksLikeKotlinGeneratedMethod(it.name) } + ?.let { _ -> val propertyNameFromGetter = member.name.let { when { it.startsWith("get") -> it.substringAfter("get") @@ -54,6 +51,10 @@ internal class KotlinNamesAnnotationIntrospector(val module: KotlinModule, val c }?.name } + // Since getter for value class (inline class) will be compiled into a different name such as "getFoo-${random}". + private fun looksLikeKotlinGeneratedMethod(methodName: String) = + methodName.run { contains("-") && (startsWith("get") || startsWith("is")) } + // since 2.11: support Kotlin's way of handling "isXxx" backed properties where // logical property name needs to remain "isXxx" and not become "xxx" as with Java Beans // (see https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html and From 5c97eab5cb10140a637ef31ab330228b13d80cff Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Fri, 28 May 2021 04:30:10 +0900 Subject: [PATCH 4/8] fix name --- .../kotlin/KotlinNamesAnnotationIntrospector.kt | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt index 8d078fef9..8a510892c 100644 --- a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt +++ b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt @@ -36,17 +36,15 @@ internal class KotlinNamesAnnotationIntrospector(val module: KotlinModule, val c private fun findImplicitPropertyNameFromKotlinPropertyIfNeeded(member: AnnotatedMethod): String? = member .takeIf { it.parameterCount == 0 && looksLikeKotlinGeneratedMethod(it.name) } ?.let { _ -> - val propertyNameFromGetter = member.name.let { - when { - it.startsWith("get") -> it.substringAfter("get") - it.startsWith("is") -> it.substringAfter("is") - else -> throw IllegalStateException("Should not get here.") - } + val propertyNameFromGetter = when { + member.name.startsWith("get") -> member.name.substringAfter("get") + member.name.startsWith("is") -> member.name.substringAfter("is") + else -> throw IllegalStateException("Should not get here.") }.replaceFirstChar { it.lowercase(Locale.getDefault()) } - member.declaringClass.kotlin.declaredMemberProperties.find { kProperty1 -> - kProperty1.javaGetter - ?.let { it == member.member && kProperty1.name != propertyNameFromGetter } + member.declaringClass.kotlin.declaredMemberProperties.find { kProperty -> + kProperty.javaGetter + ?.let { it == member.member && kProperty.name != propertyNameFromGetter } ?: false }?.name } From e60a6fd1507fe8f664c86f3957f226666372995e Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Fri, 28 May 2021 19:56:38 +0900 Subject: [PATCH 5/8] fix cond --- .../module/kotlin/KotlinNamesAnnotationIntrospector.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt index 8a510892c..cd218a02b 100644 --- a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt +++ b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt @@ -34,8 +34,9 @@ internal class KotlinNamesAnnotationIntrospector(val module: KotlinModule, val c // Use Kotlin property names as needed. private fun findImplicitPropertyNameFromKotlinPropertyIfNeeded(member: AnnotatedMethod): String? = member - .takeIf { it.parameterCount == 0 && looksLikeKotlinGeneratedMethod(it.name) } - ?.let { _ -> + .takeIf { + it.parameterCount == 0 && looksLikeKotlinGeneratedMethod(it.name) && !it.hasAnnotation(JvmName::class.java) + }?.let { _ -> val propertyNameFromGetter = when { member.name.startsWith("get") -> member.name.substringAfter("get") member.name.startsWith("is") -> member.name.substringAfter("is") From 55117c8296b1853ba2b1f453bdf257364deee310 Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Fri, 28 May 2021 20:00:10 +0900 Subject: [PATCH 6/8] Modified to use the name of KProperty unconditionally. --- .../kotlin/KotlinNamesAnnotationIntrospector.kt | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt index cd218a02b..edfbe7478 100644 --- a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt +++ b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt @@ -37,17 +37,9 @@ internal class KotlinNamesAnnotationIntrospector(val module: KotlinModule, val c .takeIf { it.parameterCount == 0 && looksLikeKotlinGeneratedMethod(it.name) && !it.hasAnnotation(JvmName::class.java) }?.let { _ -> - val propertyNameFromGetter = when { - member.name.startsWith("get") -> member.name.substringAfter("get") - member.name.startsWith("is") -> member.name.substringAfter("is") - else -> throw IllegalStateException("Should not get here.") - }.replaceFirstChar { it.lowercase(Locale.getDefault()) } - - member.declaringClass.kotlin.declaredMemberProperties.find { kProperty -> - kProperty.javaGetter - ?.let { it == member.member && kProperty.name != propertyNameFromGetter } - ?: false - }?.name + member.declaringClass.kotlin.declaredMemberProperties + .find { kProperty -> kProperty.javaGetter == member.member } + ?.name } // Since getter for value class (inline class) will be compiled into a different name such as "getFoo-${random}". From 378c3df15f13f0a42154bb1f371ac1cb18a954de Mon Sep 17 00:00:00 2001 From: Drew Stephens Date: Fri, 28 May 2021 15:24:08 -0400 Subject: [PATCH 7/8] Ignore class that disappeared MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This …Kt class disappeared. It had a (private) top-level function that was removed. --- pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pom.xml b/pom.xml index 5a1635020..b63cc7501 100644 --- a/pom.xml +++ b/pom.xml @@ -221,6 +221,11 @@ com.fasterxml.jackson.module.kotlin.ULongSerializer com.fasterxml.jackson.module.kotlin.UShortDeserializer com.fasterxml.jackson.module.kotlin.UShortSerializer + + com.fasterxml.jackson.module.kotlin.KotlinNamesAnnotationIntrospectorKt From 460923f327e4cb7b2f9f5b409f468d80dd81fd26 Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 5 Jun 2021 18:38:34 +0900 Subject: [PATCH 8/8] add getter like method support --- .../kotlin/KotlinNamesAnnotationIntrospector.kt | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt index edfbe7478..93d09f846 100644 --- a/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt +++ b/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt @@ -37,9 +37,17 @@ internal class KotlinNamesAnnotationIntrospector(val module: KotlinModule, val c .takeIf { it.parameterCount == 0 && looksLikeKotlinGeneratedMethod(it.name) && !it.hasAnnotation(JvmName::class.java) }?.let { _ -> - member.declaringClass.kotlin.declaredMemberProperties - .find { kProperty -> kProperty.javaGetter == member.member } - ?.name + member.member.kotlinFunction + ?.let { getterLike -> + // for getter like method + val name = getterLike.name + val replaceTarget = if (name.startsWith("get")) "get" else "is" + + name.substringAfter(replaceTarget).replaceFirstChar { it.lowercase(Locale.getDefault()) } + } + ?: member.declaringClass.kotlin.declaredMemberProperties // for property getter + .find { kProperty -> kProperty.javaGetter == member.member } + ?.name } // Since getter for value class (inline class) will be compiled into a different name such as "getFoo-${random}".