Search code examples
javarecursionreflectiondynamic-programmingcamunda

Java - Need to convert Flat Map<String, Object> to Nested Object


I have already written a code to convert a nested object to flat Map<string, Object>. I need your help to convert the flat Map<String, Object> to a nested object.

For example:

Class BaseModel implements Serializable{}

Class A : BaseModel{
    String test;
    int testInt;
    B b;

}

Class B : BaseModel{
    Double testDouble;
    List<C> c;
}

Class C : BaseModel{
    float testFloat;
}

An object of Class A will be represented as JSON form as below:

{
    "test": "t",
    "testInt": 1,
    "b": {
        "testDouble": 1.1,
        "c": [{
            "testFloat": 1.2
        }]
    }
}

Using my function mentioned below:

public static Map<String, Object> getDataForProcess(BaseModel model, String fieldName){

        Map<String, Object> m = new HashMap<String, Object>();

        Class<?> thisClass = null;
        try {
            if(model != null){
                thisClass = Class.forName(model.getClass().getName());

                Field[] aClassFields = thisClass.getDeclaredFields();
                for(Field f : aClassFields){
                    String fName = null;
                    if(fieldName != null && fieldName.length() > 0){
                        fName = fieldName + "_" +f.getName();
                    } else {
                        fName = f.getName();
                    }
                    if(BaseModel.class.isAssignableFrom(f.getType())){
                        BaseModel labModel = (BaseModel)f.get(model);
                        Map<String, Object> mapFromObject = getDataForProcess(labModel, fName);
                        m.putAll(mapFromObject);
                    } else if(List.class.isAssignableFrom(f.getType())){
                        @SuppressWarnings("unchecked")
                        List<BaseModel> list = (List<BaseModel>)f.get(model);
                        for(int i=0;i<list.size();i++){
                            Map<String, Object> mapFromList = getDataForProcess(list.get(i), fName+"_"+i);
                            m.putAll(mapFromList);
                        }
                    } else {
                        if(!fName.contains("serialVersionUID")){
                            m.put(fName, f.get(model));
                        }

                    }
                }
            }

            
        } catch (Exception e) {
            e.printStackTrace();
        }

        return m;
}

The nested object will be converted as:

{
    "test": "t",
    "testInt": 1,
    "b_testDouble": 1.1,
    "b_c_0_testFloat": 1.2
}

I need your help to convert the flat map back to nested object.


Solution

  • Josson can do the job in terms of Jackson JsonNode object. You can further process on the JsonNode.

    https://github.com/octomix/josson

    Deserialization

    Josson josson = Josson.fromJsonString(
        "{" +
        "    \"test\": \"t\"," +
        "    \"testInt\": 1," +
        "    \"b\": {" +
        "        \"testDouble\": 1.1," +
        "        \"c\": [{" +
        "            \"testFloat\": 1.2" +
        "        }]" +
        "    }" +
        "}");
    

    Flatten

    JsonNode flattened = josson.getNode("flatten('_')");
    System.out.println(flattened.toPrettyString());
    

    Output

    {
      "test" : "t",
      "testInt" : 1,
      "b_testDouble" : 1.1,
      "b_c_0_testFloat" : 1.2
    }
    

    Unflatten

    JsonNode unflatten = Josson.create(flattened).getNode("unflatten('_')");
    System.out.println(unflatten.toPrettyString());
    

    Output

    {
      "test" : "t",
      "testInt" : 1,
      "b" : {
        "testDouble" : 1.1,
        "c" : [ {
          "testFloat" : 1.2
        } ]
      }
    }