简体   繁体   中英

Jackson ObjectMapper returns null when Object variable is set to Private

I am given this escaped JSON

"{\"UniqueId\":[],\"CustomerOffers\":{},\"Success\":false,\"ErrorMessages\":[\"Test Message\"],\"ErrorType\":\"GeneralError\"}"

and I need to convert it to Java object using Jackson.

// https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
    compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.8'

I created the class:

public class Data {

    private List<UUID> UniqueId;
    private Map<Integer, List<Integer>> CustomerOffers;
    private Boolean Success;
    private List<String> ErrorMessages;
    private String ErrorType;

    // getter, setters
}

Then I created the method to convert it

public class Deserializing {

    public void processing(String input) {

        ObjectMapper mapper = new ObjectMapper();
        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);



        String jsonInString = "\"{\"UniqueId\":[],\"CustomerOffers\":{},\"Success\":false,\"ErrorMessages\":[\"Test Message\"],\"ErrorType\":\"GeneralError\"}\"";
        String newJSON = org.apache.commons.lang3.StringEscapeUtils.unescapeJava(jsonInString);
        newJSON= newJSON.substring(1, jsonInString.length()-1);


            try {
            // JSON string to Java object
            Data data = mapper.readValue(newJSON, Data.class); 
            System.out.println(data);

            System.out.println("Get Success "+ data.getSuccess());  // return "false" if Data object is public ; null if private
            System.out.println("Get UniqueID " + data.getUniqueId()); // return [] if Data object is public ; null if private

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Whichever variables in Data class that are set to public, then I will get the corresponding value when I call getters. Whichever variables in Data class that are set to private, then I will get null when I call getters.

Getters and Setters are always public.

I am wondering, why ObjectMapper can't map the object if it is set to private? I could set it to public, but that is not best practice.

The issue is that Jackson will always assume setSuccess() & getSuccess() will be used for a success field, not Success . JSON field names starting with uppercase letters need to be supported by @JsonProperty . Java has a convention where class members always start with lowercase letters, you can realize that by using this annotation.

When you make fields private , you force Jackson to utilize setters, and the above conflict makes it impossible to properly deserialize the Data object.

Solution is to do;

public class Data {

    @JsonProperty("UniqueId")
    private List<UUID> uniqueId;
    @JsonProperty("CustomerOffers")
    private Map<Integer, List<Integer>> customerOffers;
    @JsonProperty("Success")
    private Boolean success;
    @JsonProperty("ErrorMessages")
    private List<String> errorMessages;
    @JsonProperty("ErrorType")
    private String errorType;

    // getter&setters
}

Then you will see the values deserialized properly into a Java object;

Get success false
Get uniqueID []

By default, Jackson will only attempt to serialize public fields on the Data class (or whatever class you are trying to serialize/unserialize). However, you may configure ObjectMapper to allow it serialize all fields, regardless of visibility:

ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
Data data = mapper.readValue(newJSON, Data.class);

See here and here for more information.

In the JavaBeans specification (the universal guide for structuring Java class properties), properties are defined as starting with a lower-case letter ( errorMessages ); the accessors, because they have a prefix, capitalize it ( getErrorMessages ). Jackson uses the property names by default, so when you have a method getErrorMessages , it looks for a JSON property with the key errorMessages .

The best approach is to change your JSON; I've seen the styles errorMessages and error_messages but never ErrorMessages . If you can't do that, you can apply @JsonProperty to your properties to tell Jackson to use a different name in the JSON.

Also, another point to note: In this if class Data contains any constructor with arguments and doesn't contain an empty constructor. Then the object mapper will not be able to map the corresponding object. So in this case also it will return null.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM