Reputation: 872
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.
Upvotes: 6
Views: 20020
Reputation: 29
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.
Upvotes: 0
Reputation: 14698
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 []
Upvotes: 10
Reputation: 77196
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.
Upvotes: 2
Reputation: 521997
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.
Upvotes: 5