Reputation: 133
I am trying to parse some JSON (full example of the JSON can be seen in this Gist). I show the general structure of the JSON below:
[
{
"title": "Principles of Compiler Design",
"authors": [
"Aho",
"Ullman"
],
"publisher": "Addison Wesley",
"year": 1977
},
{
"title": "Compilers: Principles Techniques and Tools",
"authors": [
"Aho",
"Sethi",
"Ullman"
],
"publisher": "Addison Wesley",
"year": 1985
}
]
I am trying to parse the JSON with Jackson libraries, but I get the following error while testing:
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_ARRAY token
at [Source: library.json; line: 2, column: 49] (through reference chain: com.acme.datatypes.User["authors"])
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:163)
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:588)
at com.fasterxml.jackson.databind.deser.std.JdkDeserializers$StringDeserializer.deserialize(JdkDeserializers.java:90)
at com.fasterxml.jackson.databind.deser.std.JdkDeserializers$StringDeserializer.deserialize(JdkDeserializers.java:59)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:336)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:89)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:290)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:112)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2563)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1759)
at com.acme.datatypes.UserTest.main(UserTest.java:20)
Here is my code:
User Test class:
public class UserTest {
public static void main(String[] args) throws JsonParseException,
JsonMappingException, IOException {
File jsonFile = new File("library.json");
User user = null;
ObjectMapper mapper = new ObjectMapper();
user = mapper.readValue(jsonFile, User.class);
System.out.println(user.getTitle());
user = mapper.readValue(jsonFile, User.class);
System.out.println(user.getAuthors());
user = mapper.readValue(jsonFile, User.class);
System.out.println(user.getPublisher());
user = mapper.readValue(jsonFile, User.class);
System.out.println(user.getYear());
}
}
User class:
public class User {
private String authors;
private String publisher;
private String title;
private Number year;
public String getAuthors() {
return this.authors;
}
public void setAuthors(String authors) {
this.authors = authors;
}
public String getPublisher() {
return this.publisher;
}
public void setPublisher(String publisher) {
this.publisher = publisher;
}
public String getTitle() {
return this.title;
}
public void setTitle(String title) {
this.title = title;
}
public Number getYear() {
return this.year;
}
public void setYear(Number year) {
this.year = year;
}
}
Does anyone know what the problem might be? Thanks.
Upvotes: 12
Views: 60428
Reputation: 80598
Two quick things:
Your User class is defining the authors
property as a String. But in JSON its an array, so you need to use a collections or array type in your Java object. Something like:
private List<String> authors
You repeatedly parse the JSON file in your test class. You only need to parse it once, and you need to use a supertype token, since there is a list of items in the JSON (not just one). You are also using the wrong type to deserialize (User.class). Instead of all these lines:
user = mapper.readValue(jsonFile, User.class);
System.out.println(user.getTitle());
user = mapper.readValue(jsonFile, User.class); // <-- unnecessary parsing
System.out.println(user.getAuthors());
user = mapper.readValue(jsonFile, User.class); // <-- unnecessary parsing
System.out.println(user.getPublisher());
user = mapper.readValue(jsonFile, User.class); // <-- unnecessary parsing
System.out.println(user.getYear());
Just use:
List<User> userList =
mapper.readValue(jsonFile, new TypeReference<List<User>>() {});
Once you get a list of users in your test class you can iterate them using an enhanced for loop.
for(User user : userList) {
System.out.println(user.getTitle());
}
Upvotes: 17
Reputation: 388446
Since you are working with an array, you need to convert it into an array or a list
As Array
MyClass[] myObjects = mapper.readValue(json, MyClass[].class);
As List
List<MyClass> myObjects = mapper.readValue(jsonInput, new TypeReference<List<MyClass>>(){});
User
public class User {
private List<String> authors;
private String publisher;
private String title;
private Number year;
public List<String> getAuthors() {
return this.authors;
}
public void setAuthors(List<String> authors) {
this.authors = authors;
}
public String getPublisher() {
return this.publisher;
}
public void setPublisher(String publisher) {
this.publisher = publisher;
}
public String getTitle() {
return this.title;
}
public void setTitle(String title) {
this.title = title;
}
public Number getYear() {
return this.year;
}
public void setYear(Number year) {
this.year = year;
}
}
Usage:
List<User> l = mapper.readValue(new File(""),new TypeReference<List<User>>() {});
Upvotes: 4