Search code examples
javajsonjacksonmappingjson-deserialization

Parsing deeply nested JSON properties with Jackson


I am trying to find a clean way of parsing nested properties from a payload from an API.

Here is a rough generalisation of the JSON payload:

{
  "root": {
    "data": {
      "value": [
        {
          "user": {
            "id": "1",
            "name": {
              "first": "x",
              "last": "y"
            }
          }
        }
      ]
    }
  }
}

My goal is to have an array of User objects which have firstName and lastName fields.

Does anyone know a good way to parse this cleanly?

Right now I am trying to create a Wrapper class and within that have static inner classes for data, value, user etc. but this seems like a messy way of doing this just to read the array of first/last properties.

I am using restTemplate.exchange() to call the endpoint.


Solution

  • JsonPath library allows one to select only required fields and thn you can use Jackson to convert raw data to POJO class. Example solution could look as follows:

    import com.fasterxml.jackson.annotation.JsonProperty;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.type.CollectionType;
    import com.jayway.jsonpath.JsonPath;
    
    import java.io.File;
    import java.util.List;
    import java.util.Map;
    
    public class JsonPathApp {
    
        public static void main(String[] args) throws Exception {
            File jsonFile = new File("./resource/test.json").getAbsoluteFile();
    
            List<Map> nodes = JsonPath.parse(jsonFile).read("$..value[*].user.name");
    
            ObjectMapper mapper = new ObjectMapper();
            CollectionType usersType = mapper.getTypeFactory().constructCollectionType(List.class, User.class);
            List<User> users = mapper.convertValue(nodes, usersType);
            System.out.println(users);
        }
    }
    
    class User {
    
        @JsonProperty("first")
        private String firstName;
    
        @JsonProperty("last")
        private String lastName;
    
        public String getFirstName() {
            return firstName;
        }
    
        public void setFirstName(String firstName) {
            this.firstName = firstName;
        }
    
        public String getLastName() {
            return lastName;
        }
    
        public void setLastName(String lastName) {
            this.lastName = lastName;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "firstName='" + firstName + '\'' +
                    ", lastName='" + lastName + '\'' +
                    '}';
        }
    }
    

    Above code prints:

    [User{firstName='x', lastName='y'}]