takotsubo
takotsubo

Reputation: 746

Jackson add non-existen field during serialization

Mapper:

public static ObjectMapper mapper = new ObjectMapper()
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
            .setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
            .enable(SerializationFeature.INDENT_OUTPUT);

Class to serialize:

@Builder(builderClassName = "GooglePlayGameBuilder", toBuilder = true)
@JsonDeserialize(builder = GooglePlayGame.GooglePlayGameBuilder.class)
public final class GooglePlayGame  {

    @JsonProperty("Title") private final String title;
    @JsonProperty("Genre") private final String genre;
    @JsonProperty("Price") private final String price;
    @JsonProperty("Last updated") private final String lastUpdated;
    @JsonProperty("Current version") private final String currentVersion;
    @JsonProperty("Requirements") private final String requiresAndroid;
    @JsonProperty("IAP") private final String IAP;
    @JsonProperty("Contacts") private final String devEmail;

...

Add object to map and then i want to serialize my map:

public static volatile ConcurrentMap<String, GooglePlayGame> games = new ConcurrentSkipListMap<>(String.CASE_INSENSITIVE_ORDER);

Write to file:

public static void saveLibraryToFile(){
        try {
            mapper.writeValue(new File(LIBRARY_FILENAME), games);
        } catch (IOException e) {
            log.error("[Couldn't write to file] ", e.getMessage());
        }
    }

After this my JSON looks like:

{
  "Never Alone: Ki Edition" : {
    "Title" : "Never Alone: Ki Edition",
    "Genre" : "Adventures",
    "Price" : "4,99 €",
    "Last updated" : "September 15, 2016",
    "Current version" : "1.0.0",
    "Requirements" : "2.3+",
    "IAP" : "nope",
    "Contacts" : "[email protected]"
  },
...

If i will annotate my class with lombok @Getter strange field will appear:

{
  "Never Alone: Ki Edition" : {
    "iap" : "nope"
    "Title" : "Never Alone: Ki Edition",
    "Genre" : "Adventures",
    "Price" : "4,99 €",
    "Last updated" : "September 15, 2016",
    "Current version" : "1.0.0",
    "Requirements" : "2.3+",
    "IAP" : "nope",
    "Contacts" : "[email protected]"
  },

I dont understand this field:

"iap" : "nope"

From where Jackson found it? I checked my local map with logs and all fine, this field doesnt exist, but during serialization it appears.

Upvotes: 0

Views: 900

Answers (4)

@JsonAutoDetect(getterVisibility = Visibility.NONE, isGetterVisibility = Visibility.NONE

Upvotes: 0

Andreas
Andreas

Reputation: 159165

Lombok will create a getter method for field IAP named getIap(). Jackson will then auto-detect that as a property named iap. Since property names are case-sensitive, that is a distinct property from the IAP property defined by the @JsonProperty("IAP") annotation.

You have 2 choices:

  • Rename the field to iap, keep the annotation unchanged.
    Recommended, since that follows the Java naming standard.

  • Add the following annotation to the class:

    @JsonAutoDetect(getterVisibility = Visibility.NONE, isGetterVisibility = Visibility.NONE)
    

    This stops Jackson from auto-detecting properties from getter methods, i.e. only getter methods annotated with @JsonProperty would define a property. Since none of the Lombok-created getters would have that annotation, the effect would be that only annotated fields would define properties.

Upvotes: 1

user2447161
user2447161

Reputation: 277

I don't know if you have any constraint... But I recommand you use camelCase for your variable name. I believe your problem is caused by the getter generated by Lombok.

Upvotes: 1

Bill Shubert
Bill Shubert

Reputation: 536

I agree with user2447161. Lombok is trying to make a proper getter name for "IAP", but Jackson and Lombok disagree on how nonstandard variable names should become getters, so Jackson doesn't know that the two IAPs (the variable and the getter) are the same. Rename your variable "iap" and everything will be fine.

Upvotes: 1

Related Questions