-
-
Notifications
You must be signed in to change notification settings - Fork 180
Fixed serialization/deserialization failure when the name of getter
contains -
.
#451
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
b16059c
858e0c2
b67bb9a
5c97eab
e60a6fd
55117c8
378c3df
460923f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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<KClass<*>>) : 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")) } | ||
dinomite marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}?.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()) } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I haven't opened this in an IDE so could be wrong, but does this work if you use val propertyNameFromGetter = when (member.name) {
it.startsWith("get") -> it.substringAfter("get")
it.startsWith("is") -> it.substringAfter("is")
else -> throw IllegalStateException("Should not get here.")
}.replaceFirstChar { it.lowercase(Locale.getDefault()) } There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried, but it seemed that I could only write the following. 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()) } I thought it would be better to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Quick note: lower-casing may be incorrect here. Consider case of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @cowtowncoder There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I noticed that the pattern where I will revisit this later as I don't have much more time right now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure exactly how much Kotlin module changes things, but the way basic Jackson property inspection works is that it first gets all "implicit" (and explicit) names of accessors, then joins similarly named entries (by implicit name), then does renaming of grouped accessors. I have been hoping to change handling to let modules (Kotlin and Scala mostly) customize logic more to essentially "start with fields" and use different merging logic. But right now ways to override things tend to have unexpected side-effects. For this particular case, also, I suspect that if matching of accessors used case-insensitive handling (not trivial to do as retrofit but something that has been requested and seems useful), mismatch could be avoided. And like you say, could then just use name from field (implicit name or explicit annotation)/ |
||
|
||
member.declaringClass.kotlin.declaredMemberProperties.find { kProperty1 -> | ||
kProperty1.javaGetter | ||
?.let { it == member.member && kProperty1.name != propertyNameFromGetter } | ||
?: false | ||
}?.name | ||
dinomite marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
// 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('-') } |
Uh oh!
There was an error while loading. Please reload this page.