Mapping JSON data to Java POJO Class with Jackson Mapper

25,709

You don't need the @JsonRootName annotation. You can just read the tree and get the users array. Then iterate through and use ObjectMapper's readValue(JsonNode node, Class<T> class) on each node.

Note that the capitalised ID in your json requires a hint to the parser, hence the @JsonProperty(value="ID") annotation on the getter.

public class JacksonJSON {

    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        JsonNode root = mapper.readTree(JacksonJSON.class.getResourceAsStream("/users.json"));
        ArrayNode users = (ArrayNode) root.path("users");

        Iterator<JsonNode> iterator = users.getElements();
        while (iterator.hasNext()) {
            User user = mapper.readValue(iterator.next(), User.class);

            System.out.println("User id=" + user.id + " data1=" + user.data1 + " data2=" + user.data2);
        }


    }

}


class User {

    String id;
    String data1;
    String data2;

    @JsonProperty(value="ID")
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getData1() {
        return data1;
    }

    public void setData1(String data1) {
        this.data1 = data1;
    }

    public String getData2() {
        return data2;
    }

    public void setData2(String data2) {
        this.data2 = data2;
    }

}
Share:
25,709
user723858
Author by

user723858

Updated on September 07, 2020

Comments

  • user723858
    user723858 over 3 years

    I am developing an android application and I am trying to implement the processing of some Java data using the Stream capabilities of Jackson. To do this I have a few code example to run through and will explain what each does as I go.

    Here is the JSON I am working with:

    {
    "users": [
        {
            "ID": "26",
            "data1": "Momonth",
            "data2": "2011-10-30 04:34:53"
        },
        {
            "ID": "45",
            "data1": "Porto",
            "data2": "2011-10-18 05:34:00"
        },
        {
            "ID": "21",
            "data1": "Tomson",
            "data2": "2011-10-12 02:44:13"
        }
    ],
    "success": 1,
    }
    

    The code below is the POJO where this data will be stored as it iterates through each of the "users" array list items in my data:

    @JsonRootName(value = "users")
    public class User {
    
        String ID;
        String data1;
        String data2;
        ...
    
        public String getID() {
            return ID;
        }
        public void setID(String iD) {
            ID = iD;
        }
        public String getData1() {
            return data1;
        }
        public void setData1(String data1) {
            this.data1 = data1;
        }
        public String getData2() {
            return data2;
        }
        public void setData2(String data2) {
            this.data2 = data2;
        }
        ...
    
    }
    

    Now the code below I would expect to look at the JSON data and then grab the "users" array list of objects, I then for now wanted to simply print the name of each user to the LogCat to review that it works and as explained earlier I am looking to use the "" method as the data is quite large and I want to avoid memory issues.

    HttpRequest request = HttpRequest.get("http://www.site.com/android/app/getAllUsers.php");   
    final Reader reader = request.reader();
    final ObjectMapper mapper = new ObjectMapper();
    mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
    final JsonFactory factory = mapper.getFactory();
    
    try {
    
        JsonParser jp = factory.createParser(reader);
    
        while(jp.nextToken() == JsonToken.START_OBJECT) {
    
            String fieldName = jp.getCurrentName();
    
            jp.nextToken();
    
            final User a = mapper.readValue(jp.getText(), User.class);
    
        }
    } catch (JsonParseException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    } catch (IOException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
    

    However the code above doesn't work in its current state and I get the following errors from Jackson:

    09-06 11:11:25.326: W/System.err(15029): com.fasterxml.jackson.databind.JsonMappingException: Current token not START_OBJECT (needed to unwrap root name 'users'), but FIELD_NAME
    09-06 11:11:25.326: W/System.err(15029):  at [Source: java.io.InputStreamReader@432b1580; line: 1, column: 2]
    09-06 11:11:25.326: W/System.err(15029):    at com.fasterxml.jackson.databind.ObjectMapper._unwrapAndDeserialize(ObjectMapper.java:2948)
    09-06 11:11:25.326: W/System.err(15029):    at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:2858)
    09-06 11:11:25.326: W/System.err(15029):    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1569)
    09-06 11:11:25.326: W/System.err(15029):    at com.app.tool.UsersListActivity$LoadAllUsers.doInBackground(UsersListActivity.java:381)
    09-06 11:11:25.326: W/System.err(15029):    at com.app.tool.UsersListActivity$LoadAllUsers.doInBackground(UsersListActivity.java:1)
    09-06 11:11:25.326: W/System.err(15029):    at android.os.AsyncTask$2.call(AsyncTask.java:287)
    09-06 11:11:25.326: W/System.err(15029):    at java.util.concurrent.FutureTask.run(FutureTask.java:234)
    09-06 11:11:25.326: W/System.err(15029):    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
    09-06 11:11:25.326: W/System.err(15029):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
    09-06 11:11:25.326: W/System.err(15029):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
    09-06 11:11:25.326: W/System.err(15029):    at java.lang.Thread.run(Thread.java:856)
    

    I would really appreciate any help that can be given on this as I am stuck and cant go forward.

    Thanks in advance


    ******EDIT********


    Thanks for the reply and I have tried to implement the code however it still doesn't seem to work, the code I have now is below:

    protected String doInBackground(String... args) {
    
        HttpRequest request = HttpRequest.get("http://www.site.com/android/app/getAllUsers.php");
        final Reader reader = request.reader();
    
        final ObjectMapper mapper = new ObjectMapper();
        final JsonFactory factory = mapper.getFactory();
    
        try {
    
                JsonParser jp = factory.createParser(reader);
    
                JsonNode root = mapper.readTree(jp);
                ArrayNode users = (ArrayNode) root.path("users");
    
                Iterator<JsonNode> iterator = users.elements();
    
                while (iterator.hasNext()) {
                    User user = mapper.readValue(iterator.next(), User.class);
    
                    System.out.println("User Name = " + user.data1);
                }
    
            } catch (JsonParseException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
    
            return null;
    }
    

    Do you think it has anything to do with my process running in an ASYNC task or that I am accessing my JSON through a web service? The error I get is below along with the line that it shows on:

    Error Line:

    User user = mapper.readValue(iterator.next(), User.class);
    

    Error Code:

    The method readValue(JsonParser, Class<T>) in the type ObjectMapper is not applicable for the arguments (JsonNode, Class<User>)
    

    Hopefully you can help me sort this last issue out, thanks again for the assistance.