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.
Advertisement
Answer
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 []