Kévin
Kévin

Reputation: 557

Java : Merge 2 objects, same properties, multiple level

I need to merge values of 2 objects in Java, same properties.

The values of object 1 have priority over object 2. If on the other hand the value of object 1 is null, then we take the value of object 2.

So i have this objet which references other objets ( again and again )

@Data
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
public class ResourcesConfigDTO implements Serializable {
  
  private String environment;
  private String type;
  private Component component;
  private Autoscaler autoscaler;

}

Actually i use this code for merging 2 objects between them :

public static <T> T mergeObjects(T first, T second) {
        Class<?> clas = first.getClass();
        Field[] fields = clas.getDeclaredFields();
        Object result = null;
        try {
            result = clas.getDeclaredConstructor().newInstance();
            for (Field field : fields) {
                field.setAccessible(true);
                Object value1 = field.get(first);
                Object value2 = field.get(second);
                System.out.println("value1 " + value1 + " value2: " + value2);
                Object value = (value1 != null) ? value1 : value2;
                field.set(result, value);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return (T) result;
    }

But it only works with objects that only have one level, it does not work for multi level objects. I don't understand how i can fix this

Update 1 : The mergeObjects is called, the first object environment value is "d" but the objects 2 value is "null". After the isNestedObject, it calls again mergeObjects, with this "d" and "null" value, but it fails at Object value2 = field.get(second); with NPE :

public static <T> T mergeObjects(T first, T second) {
        Class<?> clas = first.getClass();
        Field[] fields = clas.getDeclaredFields();
        Object result = null;
        try {
            result = clas.getDeclaredConstructor().newInstance();
            for (Field field : fields) {
                field.setAccessible(true);
                Object value1 = field.get(first);
                Object value2 = field.get(second);

                if (!(isNestedObject(value1) && isNestedObject(value2))) {
                    // call your method recursively..
                    Object mergedValue = mergeObjects(value1, value2);
                    field.set(result, mergedValue);
                } else {
                    // do what you were doing
                    System.out.println("value1 " + value1 + " value2: " + value2);
                    Object value = (value1 != null) ? value1 : value2;
                    field.set(result, value);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return (T) result;
    }

    private static boolean isNestedObject(Object value) {

        if (value instanceof String ||
                value instanceof Integer ||
                value instanceof Double ||
                value instanceof Float ||
                value instanceof Boolean ||
                value instanceof Component ||
                value instanceof Routes ||
                value instanceof Replicas ||
                value instanceof DefaultRouteParameters ||
                value instanceof DefaultRoute ||
                value instanceof Cpu ||
                value instanceof ComponentParameters ||
                value instanceof Component ||
                value instanceof Autoscaler
                
                ) {
            return true;
        }
        return false;
    }

Upvotes: 1

Views: 915

Answers (1)

Shridutt Kothari
Shridutt Kothari

Reputation: 7394

You need to check if your field is not a primitive field or wrapper class than you need to do the same logic recursively .

Inside your for loop, once you fetch value1, you need to check if its not a primitive field or wrapper class than call the same method recursively.

Example:

for (Field field : fields) {
     field.setAccessible(true);
     Object value1 = field.get(first);
     Object value2 = field.get(second);

     if(!(isNestedObject(value1) && isNestedObject(value2))) {
         //call your method recursively..
         Object mergedValue = mergeObjects(value1, value2);
         field.set(result, mergedValue);
     } else {
         //do what you were doing 
         System.out.println("value1 " + value1 + " value2: " + value2);
         Object value = (value1 != null) ? value1 : value2;
         field.set(result, value);
     }
}

boolean isNestedObject(Object value) {
 
        if(value instanceOf String.class ||
         value instanceOf Integer.class) ||
         value instanceOf Double.class) ||
         value instanceOf Float.class) ||
         value instanceOf Boolean.class) ||
                //....add all wrapper classes here  

        ) {
                return true;
        } 
        return false;
}

Upvotes: 1

Related Questions