1

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;
    }

1 Answer 1

1

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;
}
Sign up to request clarification or add additional context in comments.

4 Comments

Your updated question is not clear, please can you elaborate more??
First call : Object value2 = field.get(second); = null (so OK, because the value is null) But on the second recursive call, field is now null, so producing NPE
add a null check wherever you get null? whats the issue?
I already tried this : Object value1 = (first != null) ? field.get(first) : null; Object value2 = (second != null) ? field.get(second) : null;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.