Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在java中合并两个复杂对象_Java_Merge - Fatal编程技术网

如何在java中合并两个复杂对象

如何在java中合并两个复杂对象,java,merge,Java,Merge,我有两个java对象,我想把它们合并成一个对象。问题是这两个对象不包含纯基元类型属性(字段),它们包含复杂类型属性(如其他类型的对象和其他类型的对象列表) 对象1:通过设置一些属性(字段)和 对象2:通过设置某些属性(字段)返回,或者它可能返回其持有但未由对象1返回的类型的新对象 对象1和对象2的类型相同 结果对象3=obj1属性+如果与obj1类型相同,则从obj 2更新属性+从obj2更新的新对象尝试使用类。getFields Field[] fields = YourClass.g

我有两个java对象,我想把它们合并成一个对象。问题是这两个对象不包含纯基元类型属性(字段),它们包含复杂类型属性(如其他类型的对象和其他类型的对象列表)

对象1:通过设置一些属性(字段)和

对象2:通过设置某些属性(字段)返回,或者它可能返回其持有但未由对象1返回的类型的新对象

对象1和对象2的类型相同


结果对象3=obj1属性+如果与obj1类型相同,则从obj 2更新属性+从obj2更新的新对象尝试使用
类。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);    
    }

使用spring提供的
org.springframework.beans.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;
}

嵌套对象解决方案

这里有一个更健壮的解决方案。它支持嵌套对象复制,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;
}
/**
*将所有属性从源复制到目标,不复制空值,并且将尝试复制任何嵌套对象
*克隆或复制到现有对象中。这是递归的。不应导致任何无限递归。
*@param dest要将道具复制到的对象(将发生变化)
*@param源
*@param dest
*@返回
*@galacessException
*@targetException
*/
公共静态T copyProperties(T dest、对象…源)抛出IllegalAccessException、InvocationTargetException{
//为了避免出现无限递归,可以将堆栈中的每个对象一次限制为一个实例
最终列表查找at=new ArrayList();
BeanUtilsBean递归Beanutils=新BeanUtilsBean(){
/**
*检查类名是否为内部名称
*@param name
*@返回
*/
专用布尔值isInternal(字符串名称){
返回name.startsWith(“java”)| | name.startsWith(“javax”)
||name.startsWith(“com.sun”)| | name.startsWith(“javax”)
||名称。startsWith(“甲骨文”);
}
/**
*重写以确保我们不会以无限递归结束
*@param dest
*@param orig
*@galacessException
*@targetException
*/
@凌驾
public void copyProperties(Object dest、Object orig)抛出IllegaAccessException、InvocationTargetException{
试一试{
//如果我们的列表中有一个对象,这意味着我们遇到了某种递归,就到此为止。
if(lookingAt.stream().anyMatch(o->o==dest)){
return;//检测到递归
}
查找添加(目的地);
超级复制属性(目标、原始);
}最后{
查找。删除(目的地);
}
}
@凌驾
公共void copyProperty(对象目标、字符串名称、对象值)
抛出IllegalAccessException,InvocationTargetException{
//不要复制空值
if(值!=null){
//尝试检查该值是否是可以使用嵌套调用克隆的pojo
如果(!value.getClass().isPrimitive()&&&!value.getClass().isSynthetic()&&!isInternal(value.getClass().getName()){
试一试{
Object prop=super.getPropertyUtils().getProperty(dest,name);
//获取当前值,如果为空,则克隆该值并将其设置为该值
if(prop==null){
super.setProperty(dest,name,super.cloneBean(value));
}否则{
//获取目标值,然后递归调用
复制属性(属性、值);
}
}捕获(无此方法例外){
返回;
}捕获(实例化异常e){
抛出新的RuntimeException(“无法克隆嵌套属性。”,e);
}
}否则{
super.copyProperty(dest、name、value);
}
}
}
};
用于(对象源:源){
recursiveBeanUtils.copyProperties(dest,source);
}
返回目的地;
}

它有点快,有点脏,但效果很好。由于它确实使用递归,并且存在无限递归的可能性,因此我将其置于安全的位置。

下面的方法将忽略SerialVersionId,遍历所有字段,并从对象a-->对象b复制非空值(如果在b中为空)。换句话说,如果b中的任何字段为null,那么如果a中的字段不为null,则从a中获取该字段

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;
    }
publicstatict-combine2Objects(ta,tb)抛出实例化异常、非法访问异常{
T result=(T)a.getClass().newInstance();
Object[]fields=Arrays.stream(a.getClass().getDeclaredFields()).filter(f->!f.getName().equals(“serialVersionUID”).collect(Collectors.toList()).toArray();
用于(对象字段对象:字段){
字段字段=(字段)字段对象;
field.set(结果,field.get(b)!=null?field.get(b):field.get(a));
}
返回结果;
}
试试这个

public <T> T objectMerge(T local, T remote, boolean toappend) throws Exception {
    Class<?> clazz = local.getClass();
    Object merged = clazz.newInstance();
    for (Field field : clazz.getDeclaredFields()) {
        field.setAccessible(true);
        Object localValue = field.get(local);
        Object remoteValue = field.get(remote);
        if (localValue != null) {
            String key = "";
            if (localValue.getClass().getSimpleName().toLowerCase().contains("map")) {
                key = "map";
            } else if (localValue.getClass().getSimpleName().toLowerCase().contains("set")) {
                key = "set";
            } else if (localValue.getClass().getSimpleName().toLowerCase().contains("list")) {
                key = "list";
            } else {
                key = localValue.getClass().getSimpleName();
            }
            switch (key) {
                case "Default":
                case "Detail":
                case "String":
                case "Date":
                case "Integer":
                case "Float":
                case "Long":
                case "Double":
                case "Object":
                    field.set(merged, (remoteValue != null) ? remoteValue : localValue);
                    break;
                case "map":
                    if (toappend) {
                        ((Map) localValue).putAll((Map) remoteValue);
                    } else {
                        localValue = (remoteValue != null) ? remoteValue : localValue;
                    }
                    field.set(merged, localValue);
                    break;
                case "list":
                    if (toappend) {
                        ((List) localValue).addAll((List) remoteValue);
                    } else {
                        localValue = (remoteValue != null) ? remoteValue : localValue;
                    }
                    field.set(merged, localValue);
                    break;
                case "set":
                    if (toappend) {
                        ((Set) localValue).addAll((Set) remoteValue);
                    } else {
                        localValue = (remoteValue != null) ? remoteValue : localValue;
                    }
                    field.set(merged, localValue);
                    break;
                default:
                    field.set(merged, this.objectMerge(localValue, remoteValue, toappend));
                    break;
            }
        }
    }
    return (T) merged;
}
public T objectMerge(T local,T remote,boolean to append)引发异常{
Class clazz=local.getClass();
对象合并=clazz.newInstance();
for(字段:clazz.getDeclaredFields()){
字段。setAccessible(true);
对象localValue=field.get(本地);
Object remoteValue=field.get(re
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;
    }
public <T> T objectMerge(T local, T remote, boolean toappend) throws Exception {
    Class<?> clazz = local.getClass();
    Object merged = clazz.newInstance();
    for (Field field : clazz.getDeclaredFields()) {
        field.setAccessible(true);
        Object localValue = field.get(local);
        Object remoteValue = field.get(remote);
        if (localValue != null) {
            String key = "";
            if (localValue.getClass().getSimpleName().toLowerCase().contains("map")) {
                key = "map";
            } else if (localValue.getClass().getSimpleName().toLowerCase().contains("set")) {
                key = "set";
            } else if (localValue.getClass().getSimpleName().toLowerCase().contains("list")) {
                key = "list";
            } else {
                key = localValue.getClass().getSimpleName();
            }
            switch (key) {
                case "Default":
                case "Detail":
                case "String":
                case "Date":
                case "Integer":
                case "Float":
                case "Long":
                case "Double":
                case "Object":
                    field.set(merged, (remoteValue != null) ? remoteValue : localValue);
                    break;
                case "map":
                    if (toappend) {
                        ((Map) localValue).putAll((Map) remoteValue);
                    } else {
                        localValue = (remoteValue != null) ? remoteValue : localValue;
                    }
                    field.set(merged, localValue);
                    break;
                case "list":
                    if (toappend) {
                        ((List) localValue).addAll((List) remoteValue);
                    } else {
                        localValue = (remoteValue != null) ? remoteValue : localValue;
                    }
                    field.set(merged, localValue);
                    break;
                case "set":
                    if (toappend) {
                        ((Set) localValue).addAll((Set) remoteValue);
                    } else {
                        localValue = (remoteValue != null) ? remoteValue : localValue;
                    }
                    field.set(merged, localValue);
                    break;
                default:
                    field.set(merged, this.objectMerge(localValue, remoteValue, toappend));
                    break;
            }
        }
    }
    return (T) merged;
}
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Supplier;

public final class PropertyMerger {

    public static <T> void mergeProperty(
            Supplier<T> sourceGetter,
            Supplier<T> targetGetter,
            Consumer<T> targetSetter
    ) {
        var source = sourceGetter.get();
        var target = targetGetter.get();

        if (!Objects.equals(source, target)) {
            targetSetter.accept(source);
        }
    }

}
PropertyMerger.mergeProperty(facebookOAuth2User::getId, existingFacebookOAuth2UserDB::getFacebookId, existingFacebookOAuth2UserDB::setFacebookId);
PropertyMerger.mergeProperty(facebookOAuth2User::getName, existingFacebookOAuth2UserDB::getName, existingFacebookOAuth2UserDB::setName);