Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error using Jackson and Json

Tags:

java

json

jackson

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.

like image 348
tribrick Avatar asked Mar 06 '13 15:03

tribrick


People also ask

How do I ignore unrecognized field Jackson?

Alternatively, you can also use @JsonIgnoreProperties annotation to ignore undeclared properties. The @JsonIgnoreProperties is a class-level annotation in Jackson and it will ignore every property you haven't defined in your POJO.

How does Jackson JSON work?

The Jackson ObjectMapper can parse JSON from a string, stream or file, and create a Java object or object graph representing the parsed JSON. Parsing JSON into Java objects is also referred to as to deserialize Java objects from JSON. The Jackson ObjectMapper can also create JSON from Java objects.

What is JSON processing exception?

Class JsonProcessingExceptionIntermediate base class for all problems encountered when processing (parsing, generating) JSON content that are not pure I/O problems. Regular IOException s will be passed through as is. Sub-class of IOException for convenience.

What is JSON mapping exception?

public class JsonMappingException extends JsonProcessingException. Checked exception used to signal fatal problems with mapping of content, distinct from low-level I/O problems (signaled using simple IOException s) or data encoding/decoding problems (signaled with JsonParseException , JsonGenerationException ).


2 Answers

Two quick things:

  1. 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

  2. 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());
}
like image 71
Perception Avatar answered Oct 19 '22 18:10

Perception


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>>() {});
like image 4
Arun P Johny Avatar answered Oct 19 '22 18:10

Arun P Johny