jackson-module-kotlin icon indicating copy to clipboard operation
jackson-module-kotlin copied to clipboard

@JsonProperty field names not respected in superclass fields

Open marshallpierce opened this issue 6 years ago • 17 comments

Repro: https://bitbucket.org/marshallpierce/repro-jackson-kotlin-inheritance/src/master/

Put briefly, serializing this:

open class SuperClass(@JsonProperty("annotationName") val someCrazyFieldName: String)
class ChildClass(s: String) : SuperClass(s)

results in the following, which uses the field name instead of what's defined in the annotation

{"someCrazyFieldName":"asdf"}

marshallpierce avatar May 10 '18 13:05 marshallpierce

and the usual question to help @apatrida: is this with 2.9.5?

cowtowncoder avatar May 10 '18 14:05 cowtowncoder

@marshallpierce it looks like it works if you use @get:JsonProperty("annotationName") instead

arekolek avatar Jul 04 '18 14:07 arekolek

As @arekolek says, target the annotation to the getter (@cowtowncoder another one where the annotations end up on the wrong thing since Kotlin has more annotation targets than Java)

apatrida avatar Jul 14 '18 19:07 apatrida

not fixed in 2.9.6

@apatrida why has this issue been closed? are you not going to fix it?

or-dvir avatar Jul 16 '18 09:07 or-dvir

@or-dvir Just using:

open class SuperClass(@get:JsonProperty("annotationName") val someCrazyFieldName: String)
class ChildClass(s: String) : SuperClass(s)

works fine

arekolek avatar Jul 16 '18 09:07 arekolek

@arekolek i am getting an error. the @get: has a red underline saying expected annotation identifier after ':'

this is my code

open class TvShowEntity(@ColumnInfo(name = "stillWatchingDb")
                        @get:@JsonProperty("stillWatching")
                        var _isStillWatching: Boolean = true)

or-dvir avatar Jul 17 '18 06:07 or-dvir

The error tells you exactly what you did wrong, you put a @ after colon instead of just the annotation identifier.

https://kotlinlang.org/docs/reference/annotations.html#annotation-use-site-targets

arekolek avatar Jul 17 '18 06:07 arekolek

face palm its working now. thanks

or-dvir avatar Jul 17 '18 07:07 or-dvir

Still fixed :-D

apatrida avatar Jul 17 '18 19:07 apatrida

ok guys... this is NOT a proper solution, but a workaround which can cause problems (admittedly, due to human error).

story time:

i got stuck on a problem for a few days now where when i deserialized an object (not even using jackson, im talking about a simple getSerializableExtra of the intent class), it would not keep its original (inherited) values. i tried many different solutions but none worked and those that did, were not good enough (too much boilerplate/duplication of code etc). after multiple days and a lot of frustration, i finally realized that actually it IS a problem with this library and the inherited values were not properly initialized in the first place. this is when i turned to google (yet again) and got to this issue page. the second i started reading the description i thought ot myself "wait a second, this sound familiar" and turns out not only have i read this before, but i actively participated in this thread lol...

the point of this story is that this solu.... i mean workaround, is an unnecessary extra step which could very easily be forgotten - and if indeed forgotten, could cause trouble.

for the creators of this library (or anyone willing to dive into this and submit a pull request), PLEASE look into this and remove this unnecessary extra step

or-dvir avatar Aug 05 '18 08:08 or-dvir

I agree the proposed solution is not intuitive. Why would the @JsonProperty annotation on the val work on a normal class but not on a superclass? I feel this needs a proper fix.

fransflippo avatar May 25 '20 07:05 fransflippo

I would like to have a fix as well

TomWolk avatar Dec 23 '20 08:12 TomWolk

I am using java and jackson version 2.12.4 and still encounter this same problem. Annotating the getter is not a good approach because I am using lombok.

nicolasmafra avatar Sep 20 '21 22:09 nicolasmafra

@nickmafra @or-dvir A good first step towards getting this fixed would be to make a pull request that uses @marshallpierce's provided reproduction to create a failing test alongside the other issues we have https://github.com/FasterXML/jackson-module-kotlin/tree/2.13/src/test/kotlin/com/fasterxml/jackson/module/kotlin/test/github/failing

dinomite avatar Sep 21 '21 15:09 dinomite

And just to make sure: test reproductions can not use Lombok directly -- they must use results of Lombok's processing, but Jackson does not (and can not) know anything about that processing: databind and Kotlin modules simple see whatever Lombok's bytecode processor gives. So using Lombok itself is fine but test reproductions cannot use it.

cowtowncoder avatar Sep 22 '21 04:09 cowtowncoder

Agreed. The example at the top of this issue is perfect because it has no dependencies beyond those that j-m-k itself uses https://bitbucket.org/marshallpierce/repro-jackson-kotlin-inheritance/src/master/

dinomite avatar Sep 22 '21 10:09 dinomite

There are significant difficulties in fixing this problem.

First, the annotations given to constructor parameters on Kotlin are not carried over to the constructors of subclasses. This means that this annotation cannot be referenced during processing of the subclass. Therefore, to solve this problem, we need to reflect the annotations collected by traversing the parent class to the class being processed.

Although it is theoretically possible to do this, but it would create other problems, such as the following

  • More reflection processing is required at initialization time for all classes
  • Need to implement very complex and difficult-to-specify processing
    • Determining which constructors to target in the base class (it is difficult to know in reflection which constructors in the base class are being called)
    • Determination of parameters to be processed (not only names in Kotlin, but also JsonProperty, etc. need to be considered?)

I agree that this behavior is not good. However, I think it is difficult to implement a feature that causes so many problems when workarounds exist and only occur in limited circumstances. It may be possible to simplify the implementation by limiting the situation, but in that case, I think it should be implemented as custom by individual users.

For those who want to implement Here is an example of an implementation that copies annotations from another constructor. https://github.com/ProjectMapK/jackson-module-kogera/blob/develop/src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinClassIntrospector.kt

k163377 avatar Mar 03 '23 16:03 k163377

Similar issues are summarized in #658. This issue is closed.

k163377 avatar Apr 02 '23 05:04 k163377