Skip to content
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

Unexpected serialization of "internal" properties #71

Closed
enerdgumen opened this issue May 30, 2017 · 17 comments
Closed

Unexpected serialization of "internal" properties #71

enerdgumen opened this issue May 30, 2017 · 17 comments
Labels
pr-welcome Issue for which progress most likely if someone submits a Pull Request

Comments

@enerdgumen
Copy link

A property with "internal" visibility is serialized with the unexpected "$backend" suffix, i.e.:

open class Identifiable {
    internal var identity: Long? = null
}

is serialized as:

{"identity$backend": null}
@enerdgumen
Copy link
Author

Similarly, if you want ignore such properties, you must include the "$backend" suffix in the property name:

@JsonIgnoreProperties("identity\$backend")

@apatrida
Copy link
Member

apatrida commented Jun 1, 2017

The Kotlin module is not involved in property selection, and the Java code doesn't know about internal properties. @cowtowncoder is there a way for a module to imply JsonIgnore for some properties?

@cowtowncoder
Copy link
Member

@apatrida Nothing specific comes to mind, although perhaps overriding methods in AnnotationIntrospector could work. Specifically findNameForDeserialization and findNameForSerialization could block auto-inclusion by returning null if internal modifier is detected (or, if not, perhaps there is naming convention to use).
This would have the benefit of being overridable by explicit annotations, should user actually want to include.
Or, perhaps overriding hasIgnoreMarker() to return true with similar logic.

@apatrida
Copy link
Member

Ok, I can take a look at it, but likely i would want this to be a feature switch, because I'm not sure if internal should always mean 'exclude' .... does package local in Java get excluded @cowtowncoder ?

@cowtowncoder
Copy link
Member

@apatrida Package local inclusion depends on both per-accessor minimum levels (only public getters and fields are auto-discovered; but all levels of setters), and association by naming (meaning that public getter/setter can "pull in" similarly named non-public field).

So while non-public fields are not auto-discovered, by default, they may be included if there is matching public accessors, for purpose of setting value.

@MikeRippon
Copy link

(Note for other people that struggle to find this on google :))
@JsonIgnore also does not work with internal properties for this same reason. A workaround is to declare property as public.

@jrgonzalezg
Copy link

jrgonzalezg commented Aug 9, 2018

To define the serialized name for the internal property to something else you can use @field:JsonProperty("name") so the annotation is applied to the field overriding the name$module default. Also @field:JsonIgnore probably works for ignoring it.

@jrgonzalezg
Copy link

@jillesvangurp
Copy link

@jrgonzalezg also ran into this. Your suggestion nearly works except I had to use @get:JsonIgnore to make it stop serializing my internal property. I'm guessing jackson looks explicitly at the getters rather than the field itself.

@jrgonzalezg
Copy link

I wrote previous comment without being in front of a computer, so didn't check the details.

There is no single solution cause it depends on actual usage and on the class and the targets generated. For immutable data classes for instance I am using now both @get:JsonProperty and @param:JsonProperty for each field. @get applies to the getter and it is used when the class needs to be serialized to retrieve the value of the field and the name to use on the written json. And @param annotation applies to the data class constructor parameter and it is used on deserialization to pass the deserialized field value on that position when creating an instance of the data class. That leads to consistent bidirectional serialization working for immutable data classes.

But for other custom classes you may need to specify something else like a @set and there may be cases (or other libraries) were you may need @field or where @field or @param are not possible cause those targets are not available, so there is no single recipe.

@apatrida
Copy link
Member

The workaround from @jrgonzalezg is the only option currently.

@apatrida apatrida reopened this Oct 29, 2019
@apatrida
Copy link
Member

Now that I wrote that, it would be possible to un-mangle names like this if needed. Maybe, I would have to think about it and the patterns. It would be fragile because we would be coding to internal naming conventions that could change with ABI versions in the future.

@apatrida
Copy link
Member

For example, now the generated naming is:

{"identity$jackson_module_kotlin":null}

apatrida pushed a commit that referenced this issue Oct 29, 2019
… is affecting how Jackson sees the property names, and is ugly when serializing as JSON
@korda
Copy link

korda commented Apr 22, 2021

I recently run into this problem and it turned out that someone has removed some lines of code that I didn't even remember why I have written, but apparently this helps with some problems we had with Koltlin and Jackson and indeed it "fixes" this issue too.

This is objectMapper configuration we use that "fixes" this issue (that is, no more annoying suffixes for your data classes):

			objectMapper.setVisibility(ObjectMapper().getSerializationConfig().getDefaultVisibilityChecker()
				.withFieldVisibility(JsonAutoDetect.Visibility.ANY)
				.withGetterVisibility(JsonAutoDetect.Visibility.NONE)
				.withIsGetterVisibility(JsonAutoDetect.Visibility.NONE)
				.withSetterVisibility(JsonAutoDetect.Visibility.NONE)
				.withCreatorVisibility(JsonAutoDetect.Visibility.NONE)
			)

(obv, it has bigger effect than that and it may break some other stuff since it affects how properties are handled)

@cowtowncoder cowtowncoder added the pr-welcome Issue for which progress most likely if someone submits a Pull Request label Nov 21, 2022
@cowtowncoder
Copy link
Member

@Spikhalskiy here's an older issue that I had forgotten about that'd be good to tackle. Not sure if improvements into name-mangling configurability would help Kotlin module automatically remove this odd suffix.

@k163377
Copy link
Contributor

k163377 commented Feb 19, 2023

Memo :
This problem is caused by the getter name of the internal property generated by Kotlin being different from how it looks on Kotlin.

internal class A {
    internal var number: Int? = null
}
// decompiled
public final class A {
   @Nullable
   private Integer number;

   @Nullable
   public final Integer getNumber$jackson_module_kotlin() {
      return this.number;
   }

   public final void setNumber$jackson_module_kotlin(@Nullable Integer var1) {
      this.number = var1;
   }
}

It could be fixed by modifying KNAI.findImplicitPropertyName and truncating after the $.
However, this method will cause the same problem as #434.

Personally, I would solve this problem by implementing #630.

@k163377
Copy link
Contributor

k163377 commented Mar 3, 2023

The issue of property names in the serialization result differing from the definition in Kotlin will be addressed in #630.
This issue be closed as a duplicate.

@k163377 k163377 closed this as completed Mar 3, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pr-welcome Issue for which progress most likely if someone submits a Pull Request
Projects
None yet
Development

No branches or pull requests

8 participants