How to combine two complex objects in java

I have two java objects and I want to combine them into one object. The problem is that two objects do not contain properties of a simple primitive type (field), which contain complex properties of a type (for example, an object of another type and a list of objects of another type).

Object 1: returns by creating some properties (fields) and

Objects 2: returns by setting some properties (fields) or can return new objects of the type that it stores, but does not return object 1.

Both object 1 and object 2 are of the same type.

Result object 3 = properties obj1 + update properties from obj 2 if the same type as obj1 + new updated object from obj2

+5
source share
3

org.springframework.beans.BeanUtils org.springframework.beans.BeanUtils spring. Apache Commons BeanUtils, , , Springs , .

public static <T> T combine2Objects(T a, T b) throws InstantiationException, IllegalAccessException {
    // would require a noargs constructor for the class, maybe you have a different way to create the result.
    T result = (T) a.getClass().newInstance();
    BeanUtils.copyProperties(a, result);
    BeanUtils.copyProperties(b, result);
    return result;
}

noargs, ,

public static <T> T combine2Objects(T a, T b, T destination) {
    BeanUtils.copyProperties(a, destination);
    BeanUtils.copyProperties(b, destination);
    return destination;
}

, - :

public static void nullAwareBeanCopy(Object dest, Object source) throws IllegalAccessException, InvocationTargetException {
    new BeanUtilsBean() {
        @Override
        public void copyProperty(Object dest, String name, Object value)
                throws IllegalAccessException, InvocationTargetException {
            if(value != null) {
                super.copyProperty(dest, name, value);
            }
        }
    }.copyProperties(dest, source);
}

. , 1+ , .

/**
 * Copies all properties from sources to destination, does not copy null values and any nested objects will attempted to be
 * either cloned or copied into the existing object. This is recursive. Should not cause any infinite recursion.
 * @param dest object to copy props into (will mutate)
 * @param sources
 * @param <T> dest
 * @return
 * @throws IllegalAccessException
 * @throws InvocationTargetException
 */
public static <T> T copyProperties(T dest, Object... sources) throws IllegalAccessException, InvocationTargetException {
    // to keep from any chance infinite recursion lets limit each object to 1 instance at a time in the stack
    final List<Object> lookingAt = new ArrayList<>();

    BeanUtilsBean recursiveBeanUtils = new BeanUtilsBean() {

        /**
         * Check if the class name is an internal one
         * @param name
         * @return
         */
        private boolean isInternal(String name) {
            return name.startsWith("java.") || name.startsWith("javax.")
                    || name.startsWith("com.sun.") || name.startsWith("javax.")
                    || name.startsWith("oracle.");
        }

        /**
         * Override to ensure that we dont end up in infinite recursion
         * @param dest
         * @param orig
         * @throws IllegalAccessException
         * @throws InvocationTargetException
         */
        @Override
        public void copyProperties(Object dest, Object orig) throws IllegalAccessException, InvocationTargetException {
            try {
                // if we have an object in our list, that means we hit some sort of recursion, stop here.
                if(lookingAt.stream().anyMatch(o->o == dest)) {
                    return; // recursion detected
                }
                lookingAt.add(dest);
                super.copyProperties(dest, orig);
            } finally {
                lookingAt.remove(dest);
            }
        }

        @Override
        public void copyProperty(Object dest, String name, Object value)
                throws IllegalAccessException, InvocationTargetException {
            // dont copy over null values
            if (value != null) {
                // attempt to check if the value is a pojo we can clone using nested calls
                if(!value.getClass().isPrimitive() && !value.getClass().isSynthetic() && !isInternal(value.getClass().getName())) {
                    try {
                        Object prop = super.getPropertyUtils().getProperty(dest, name);
                        // get current value, if its null then clone the value and set that to the value
                        if(prop == null) {
                            super.setProperty(dest, name, super.cloneBean(value));
                        } else {
                            // get the destination value and then recursively call
                            copyProperties(prop, value);
                        }
                    } catch (NoSuchMethodException e) {
                        return;
                    } catch (InstantiationException e) {
                        throw new RuntimeException("Nested property could not be cloned.", e);
                    }
                } else {
                    super.copyProperty(dest, name, value);
                }
            }
        }
    };


    for(Object source : sources) {
        recursiveBeanUtils.copyProperties(dest, source);
    }

    return dest;
}

, . , , .

+17

class.getFields

    Field[] fields = YourClass.getFields();
    for (Field field : fields) {
         // get value
         YourObject value = field.get(objectInstance);
         // check the values are different, then update 
         field.set(objetInstance, value);    
    }
+2

The method below will ignore serialVersionUID, iterate over all fields, and copy non-zero values ​​from object a → object b if they are zero in b. In other words, if any field is zero in b, take it from a if it is not equal to zero.

public static <T> T combine2Objects(T a, T b) throws InstantiationException,IllegalAccessException{
            T result = (T) a.getClass().newInstance();
            Object[] fields = Arrays.stream(a.getClass().getDeclaredFields()).filter(f -> !f.getName().equals("serialVersionUID")).collect(Collectors.toList()).toArray();
            for (Object fieldobj : fields) {
                Field field = (Field) fieldobj;
                field.set(result, field.get(b) != null ? field.get(b) : field.get(a));
            }
            return result;
    }
0
source

All Articles