-1

I have a Java object as shown below. I need to iterate through this nested object and fetch all values for one field. Ex 'time' for below java object.

If it is a list, I can use java 8 filters. But how to do this on an object?

Also, I need to do it in a generic way.

    {
  "dataType": "Node",
  "totalCount": 1,
  "count": 1,
  "startIndex": 0,
  "data": [
    {
      "id": "a4b7a825f67930965747445709011120-Node-6f638b5e71debd5807ec7fb73b9dc20b",
      "refObjects": {},
      "tid": "a4b7a825f67930965747445709011120",
      "creationDate": "2018-09-20T06:55:36.742+0000",
      "lmd": "2018-09-20T06:55:36.799+0000",
      "exceptions": [
        {
          "name": "projectedInventory",
          "status": "Stockout",
          "severity": "High",
          "time": "2018-09-20T00:00:00.000+0000"
        }
      ],
      "criticalities": [
        "HotItem"
      ],
      "customerName": "Best Buys",
      "supplierName": "Samsung",
      "customerItemName": "Ship to item name",
      "nodeType": "inventory",
      "supplierItemName": "Ship from item name",
      "shipToSiteName": "IT06",
      "shipFromSiteName": "IT07",
      "status": "Active",
      "lob": "HC",
      "processType": "demandSupply",
      "measures": {
        "maxInventory": [
          {
            "refObjects": {},
            "time": "2018-09-26T00:00:00.000+0000",
            "quantity": 0
          },
          {
            "refObjects": {},
            "time": "2018-09-27T00:00:00.000+0000",
            "quantity": 0
          }
        ],
        "maxDistribution": [
          {
            "refObjects": {},
            "time": "2018-09-28T00:00:00.000+0000",
            "quantity": 0
          },
          {
            "refObjects": {},
            "time": "2018-09-29T00:00:00.000+0000",
            "quantity": 0
          },
          {
            "refObjects": {},
            "time": "2018-09-30T00:00:00.000+0000",
            "quantity": 0
          },
          {
            "refObjects": {},
            "time": "2018-10-07T00:00:00.000+0000",
            "quantity": 0
          },
          {
            "refObjects": {},
            "time": "2018-10-14T00:00:00.000+0000",
            "quantity": 0
          },
          {
            "refObjects": {},
            "time": "2018-10-21T00:00:00.000+0000",
            "quantity": 0
          },
          {
            "refObjects": {},
            "time": "2018-10-28T00:00:00.000+0000",
            "quantity": 0
          },
          {
            "refObjects": {},
            "time": "2018-11-04T00:00:00.000+0000",
            "quantity": 0
          },
          {
            "refObjects": {},
            "time": "2018-11-25T00:00:00.000+0000",
            "quantity": 0
          }
        ]
      },
      "customerItemDescription": "EXP08CN1W6  PORTABLE AIR CONDITIONER HC",
      "materialGroup": "ELX",
      "shipToSiteDescription": "IT - BE10 Porcia Hub"
    }
  ],
  "typeCounts": null
}

Now I want to retrieve all the values of "time" field and save it in a list. What's the best approach to do this?

The output should be something like this:

{
  "time": [
    "2018-12-30T00:00:00.000+0000",
    "2018-08-24T12:00:00.000+0000"
  ]
}
Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197

2 Answers2

1

You can use reflection also ,but apache-commons makes it easier. the method that I have written below takes two argument one is your POJO object and another one is empty list.and it will return the same list by populating all the value of property "time" in your input object even if there are nested object. in else if I have added one condition where I am checking if className contains "com.your.packageName" or not, this is because here I am assuming that all your POJO(which can be nested in your input object) are stored in a package "com.your.packageName" so if you have your all POJOs stored at one location then you replace it with your package name. Add following dependency for the common-beanutills.

 <groupId>commons-beanutils</groupId>
 <artifactId>commons-beanutils</artifactId>
 <version>1.9.2</version>

    import org.apache.commons.beanutils.BeanMap;
    import org.apache.commons.beanutils.PropertyUtilsBean;

     private static List<String> getPropertyValue(Object myObj, List<String> timeList) {
            final BeanMap beanMap = new BeanMap(myObj);
            PropertyUtilsBean pp = new PropertyUtilsBean();
            beanMap.keySet().stream().forEach(x -> {
                try {
                     String propertyName= ""+x;
                     //GET THE CLASS TYPE OF PROPERTY
                     String proprtyTypeClassName=""+pp.getPropertyType((Object)myObj,propertyName);
                     System.out.println(propertyName+"  "+proprtyTypeClassName);
                     if(propertyName.equals("time")) {
                         //GET THE VALUE OF A propertyName FROM object myObj
                         timeList.add((String)pp.getProperty(myObj, propertyName));
                     }
                     else if(proprtyTypeClassName.contains("com.your.packageName")) {
//recursively call same method if value is another POJO object nested inside
                         getPropertyValue(pp.getProperty(myObj, propertyName),timeList);
                     }
                } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
                    e.printStackTrace();
                }
            });
            return timeList;
        }

let me know in case you have any doubt.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Nawnit Sen
  • 973
  • 2
  • 7
  • 14
0

Thank you so much. I was trying some solutions and found one below. Let me know if this also looks correct:

package com.company.dct.exec.lib.relationships.util;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jayway.jsonpath.JsonPath;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component("objectPathValuesExtractor")
public class ObjectPathValuesExtractor {
    private static final Logger LOGGER = LoggerFactory.getLogger(ObjectPathValuesExtractor.class);

    /**
     * Extract values for a given path from current object.
     *
     * @param object the object
     */

    public <T extends Object> T extractValues(Object object, String pathExpression) {
        T values = null;
        if (object == null) {
            return values;
        }
        try {
            ObjectMapper mapper = new ObjectMapper();
            mapper.setDefaultPropertyInclusion(JsonInclude.Value.construct(JsonInclude.Include.ALWAYS, JsonInclude.Include.NON_NULL));
            Map<String, Object> mappedObject = mapper.convertValue(object, Map.class);
            values = JsonPath.read(mappedObject, pathExpression);
        } catch (Exception e) {
            LOGGER.error("Failed to load alert referenced object.", e);
        }
        return values;
    }
}

Here I am using
compile group: 'com.jayway.jsonpath', name: 'json-path', version: '2.4.0' from apache

And then i'm calling this function

List<Map<String, Extensible>> refObjects = objectPathValuesExtractor.extractValues(object, "$..time");