-
-
Notifications
You must be signed in to change notification settings - Fork 177
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
Conversation
7e5ecf7
to
858e0c2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks good to me, just a few comments
src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt
Show resolved
Hide resolved
src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt
Outdated
Show resolved
Hide resolved
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 comment
The 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 when (member.name)
and drop the .let {}
?
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 comment
The 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 let
because member.name
would be repeated many times.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quick note: lower-casing may be incorrect here. Consider case of getURL()
which should produce, I think, URL
, as per Java Beans definition. But if code above simply lower-cases the first character, it'd return uRL
.
(Jackson itself has bit of inconsistency, originally returning url
for that case, lower-casing all leading upper-case chars; but then adding option for producing URL
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cowtowncoder
In this scene, if the name retrieved from the getter
is different from the name of the property, the name of the property will be adopted.
In other words, even if the name retrieved from the getter
is wrong, the name of the property (= expected value) will be adopted as a result.
For this reason, I thought the problem you pointed out would not occur here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed that the pattern where getter
is named with @JvmGetter
@get:JvmName
doesn't cover some areas.
It looks like the property names should not be used in this pattern.
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 comment
The 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 comment
The 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.
In this scheme, then, if implicit name from getter does not match those of fields, they would infer different non-related properties.
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)/
src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinNamesAnnotationIntrospector.kt
Outdated
Show resolved
Hide resolved
src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/github/Github356.kt
Show resolved
Hide resolved
@cowtowncoder @dinomite
1 If a Therefore, if the 2 First, if strictly compare the name of the Therefore, I decided to use |
This …Kt class disappeared. It had a (private) top-level function that was removed.
That makes sense to me, but @cowtowncoder is better at evaluating those sorts of things than I. |
I think I agree that @k163377 I don't know how well you know |
@dinomite @cowtowncoder I don't think I have enough knowledge and organization of the problem to tackle this issue. I am very sorry for the trouble I caused you with my half-hearted understanding. Additional contextAs for The I'm thinking of setting up a separate PR with only a light refactor and removal of this decision, how about that? |
Thanks for all the effort in exploring these ideas! Things don't always work out. Separate PRs for testing that currently-untested |
@k163377 We've merged that other PR, is there still work to do here? |
The current implementation determines whether a
getter
is for anvalue class
(inline class
) by checking whether the name of thegetter
contains-
.On the other hand, in
Kotlin
, it is possible to create agetter
with-
in its name by escaping with@JvmName
or`
, and serialization/deserialization will fail in such a pattern.In this PR, I added a test case and modified it so that if there is a discrepancy between a property name retrieved from
getter
and a property name retrieved fromKProperty
, the latter is used.Also, this change supports not only the
value class
, but all patterns where thegetter
is automatically compiled to a form containing-
.