Frank
Frank

Reputation: 3

How to deserialize JSON string using standard setters

I am using jackson-core, databind, annotations 2.3.3 jars. I have the following simple class

public class ClassA {
    private int value;

    public int getValue() {
        return this.value;
    }

    public void setValue(int value) {
        this.value = value;
    }
}

And here is the code to try to deserialize a JSON string to the object:

import com.fasterxml.jackson.databind.ObjectMapper;

...

final ObjectMapper objectMapper = new ObjectMapper();
ClassA request = objectMapper.readValue("{\"Value\": 1}", ClassA.class);

But I am getting the following error: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "Value" (class ClassA), not marked as ignorable (one known property: "value"]) at [Source: java.io.StringReader@3bff5976; line: 1, column: 12] (through reference chain: ClassA["Value"])

If I changed the JSON string to lower case then it worked. I thought Jackson would be able to map the value to the setter by following the setter convention. I understand i could add JsonProperty annotation to ClassA to make it work but I cannot modify ClassA in my situation.

I also tried explicitly enabling the following mapping features before calling readValue, but it still got the same error:

import com.fasterxml.jackson.databind.MapperFeature;

...

objectMapper.enable(MapperFeature.AUTO_DETECT_GETTERS);
objectMapper.enable(MapperFeature.AUTO_DETECT_SETTERS);

How can I have Jackson bind to standard getters/setters (getXxx and setXxx) without specify annotation to the class being bound?

Thanks!

Upvotes: 0

Views: 3808

Answers (2)

mkobit
mkobit

Reputation: 47269

It looks like this is happening because of the default PropertyNamingStrategy provided by Jackson. From the documentation:

In absence of a registered custom strategy, default Java property naming strategy is used, which leaves field names as is, and removes set/get/is prefix from methods (as well as lower-cases initial sequence of capitalized characters).

The mapper default uses the Java default property naming strategy. If your JSON properties are Pascal Case (not sure because you only provided 1 property) then you can give the mapper the PascalCaseStrategy.

final ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setPropertyNamingStrategy(new PropertyNamingStrategy.PascalCaseStrategy());
ClassA request = objectMapper.readValue("{\"Value\": 1}", ClassA.class);

Upvotes: 1

Sotirios Delimanolis
Sotirios Delimanolis

Reputation: 279990

Jackson follows bean naming conventions.

I understand i could add JsonProperty annotation to ClassA to make it work but I cannot modify ClassA in my situation.

That's where mixins come in handy. Create an abstract class that has the same method declarations (same getters for example) as ClassA and annotate them with the appropriate @JsonProperty annotation. You then register the mixin with the ObjectMapper and voila! The ObjectMapper will now use the mixin class as a template for serializing and deserializing ClassA.

Upvotes: 0

Related Questions