I would like to iterate a big Json's properties and sub properties name with jackson

Viewed 322

My final aim is to get all the properties name and its types from a local file path.

Example 
{
  "description": "Something",
  "id": "abc.def.xyzjson#",
  "type": "object",
  "properties": {
    "triggerTime": {
      "type": "string",
      "description": "Time of adjustment event",
      "source": "ab.cd",
      "pattern": "something",
      "required": true
    },
    "customerId": {
      "type": "string",
      "description": "Something",
      "source": "ef.gh",
      "required": true
    }, ..... many more properties 

Under some properties, there are sub-properties and their Type. I want final Output as- triggerTime String customerId String (also sub)

2 Answers

My advice is to load the json into Map<String, Object> and then to recursively iterate on the map and collect the data you require

Here is the entire solution for you

public class JsonProperties
{
    @SuppressWarnings("unchecked")
    public static void main(String[] args)
    {
        ObjectMapper mapper = new ObjectMapper();
        try (InputStream is = new FileInputStream("C://Temp/xx.json")) {
            Map<String, Object> map = mapper.readValue(is, Map.class);
            List<Property> properties = getProperties((Map<String, Object>)map.get("properties"));
            System.out.println(properties);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @SuppressWarnings("unchecked")
    public static List<Property> getProperties(Map<String, Object> propertiesMap) {

        List<Property> propertiesList = new ArrayList<>();

        // iterate on properties
        for (Map.Entry<String, Object> propertyEntry : propertiesMap.entrySet()) {
            Property property = new Property();
            property.name = propertyEntry.getKey();
            Map<String, Object> propertyAttrsMap = (Map<String, Object>)propertyEntry.getValue();
            property.type = (String)propertyAttrsMap.get("type");
            // recursively get sub properties 
            if (propertyAttrsMap.containsKey("properties")) {
                property.subProperties = getProperties((Map<String, Object>)propertyAttrsMap.get("properties"));
            }
            propertiesList.add(property);
        }

        return propertiesList;
    }

    public static class Property {
        public String name;
        public String type;
        public List<Property> subProperties = new ArrayList<>();

        @Override
        public String toString() {
            return name + " " + type + " " + subProperties;
        }
    }
}

using this sample input

{
  "description": "Something",
  "id": "abc.def.xyzjson#",
  "type": "object",
  "properties": {
    "triggerTime": {
      "type": "string",
      "description": "Time of adjustment event",
      "source": "ab.cd",
      "pattern": "something",
      "required": true
    },
    "customerId": {
      "type": "string",
      "description": "Something",
      "source": "ef.gh",
      "required": true
    },
    "complex": {
      "type": "string",
      "description": "Something",
      "source": "ef.gh",
      "required": true,
      "properties": {
        "sub1": {
          "type": "int",
          "description": "sub1",
          "source": "ab.cd",
          "required": true
        },
        "sub2": {
          "type": "short",
          "description": "sub2",
          "source": "ab.cd",
          "required": true
        }
      }
    }
  }
}

produces the following output:

[triggerTime string [], customerId string [], complex string [sub1 int [], sub2 short []]]

There are multiple solutions to your problem.

One would be what Sharon suggested with just iterating the big map.

Another solution however would be to create wrapper classes ( POJOs ) to work with, which also could provide other useful aspects depending on your scale and use case.

public class YourJsonObject {

private String description;

private string id;

private String object;

private JsonProperties properties;

public YourJsonObject() {

}

public JsonProperties getProperties(){
return properties;
}

public void setProperties(JsonProperties properties){
this.properties = properties;
}

public String getDescription(){
return description;
}

public void setDescription(String description) {
this.description= description;
}

public String getId(){
return id;
}

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

//and so on with the getter setter
}


//The class JsonProperties used in YourJsonObject
public class JsonProperties{

private TriggerTime triggertime;

private Customer customerId;

public JsonProperties() {

}

public TriggerTime getTriggertime(){
return triggertime;
}

//and so on

}

Then somewhere else you can just do this:

ObjectMapper mapper = new ObjectMapper(); // create once, reuse
yourJsonObject example = new yourJsonObject(); // have your POJO you want to save
mapper.writeValue(new File("result.json"), example);

To read you can just use:

ObjectMapper mapper = new ObjectMapper(); // create once, reuse
yourJsonObject value = mapper.readValue(new File("data.json"), yourJsonObject .class); // data.json is the json file you want to read. Else you can also pass a String into it with method overloading.

Both snippets are taken from my linked wiki article from jackson themselves.

Jackson should automatically be able to parse this POJO to an equivalent JSON if configured correctly. Note: Jackson has to be globally registered and has to know about it. Please read the wiki of what you use to know about it. Jackson in 5 Minutes

Related