Java 为了将非空属性从对象复制到另一个对象的助手?(爪哇)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1301697/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 08:00:39  来源:igfitidea点击:

Helper in order to copy non null properties from object to another ? (Java)

javahelper

提问by Arthur Ronald

See the following class

看下面的课

public class Parent {

    private String name;
    private int age;
    private Date birthDate;

    // getters and setters   

}

Suppose i have created a parent object as follows

假设我创建了一个父对象如下

Parent parent = new Parent();

parent.setName("A meaningful name");
parent.setAge(20);

Notice according to code above birthDate property is null. Now i want to copy ONLY non null properties from parent object to another. Something like

请注意,根据上面的代码birthDate 属性为空。现在我只想将非空属性从父对象复制到另一个。就像是

SomeHelper.copyNonNullProperties(parent, anotherParent);

I need it because i want to update anotherParent object without overrides its non null with null values.

我需要它,因为我想更新 anotherParent 对象而不用空值覆盖其非空值。

Do you know some helper like this one ?

你认识这样的帮手吗?

I accept minimal code as answer whether no helper in mind

我接受最少的代码作为答案是否没有帮助

regards,

问候,

采纳答案by SergiGS

I supose you already have a solution, since a lot of time has happened since you asked. However, it is not marked as solved, and maybe I can help other users.

我假设您已经有了解决方案,因为自从您提出要求以来已经发生了很多时间。但是,它没有标记为已解决,也许我可以帮助其他用户。

Have you tried by defining a subclass of the BeanUtilsBeanof the org.commons.beanutilspackage? Actually, BeanUtilsuses this class, so this is an improvement of the solution proposed by dfa.

你有没有定义的一个子类试过BeanUtilsBean了的org.commons.beanutils包?实际BeanUtils使用了这个类,所以这是对dfa提出的方案的改进。

Checking at the source codeof that class, I think you can overwrite the copyPropertymethod, by checking for null values and doing nothing if the value is null.

检查该类的源代码,我认为您可以copyProperty通过检查空值并在值为空时不执行任何操作来覆盖该方法。

Something like this :

像这样的事情:

package foo.bar.copy;
import java.lang.reflect.InvocationTargetException;
import org.apache.commons.beanutils.BeanUtilsBean;

public class NullAwareBeanUtilsBean extends BeanUtilsBean{

    @Override
    public void copyProperty(Object dest, String name, Object value)
            throws IllegalAccessException, InvocationTargetException {
        if(value==null)return;
        super.copyProperty(dest, name, value);
    }

}

Then you can just instantiate a NullAwareBeanUtilsBeanand use it to copy your beans, for example:

然后你可以实例化 aNullAwareBeanUtilsBean并使用它来复制你的 bean,例如:

BeanUtilsBean notNull=new NullAwareBeanUtilsBean();
notNull.copyProperties(dest, orig);

回答by dfa

you can use Apache Common BeanUtils, more specifically the copyProperties helper in BeanUtils class:

您可以使用Apache Common BeanUtils,更具体地说是 BeanUtils 类中的 copyProperties 助手

 BeanUtils.copyProperties(parent, anotherParent);   

however why do you want copy only non-null properties? if a property in parentis null, by simply copying it you have null also in anotherParentright?

但是为什么你只想复制非空属性?如果一个属性parent为空,通过简单地复制它,你也有空值,anotherParent对吗?

Just guessing... you want to update a bean with another bean?

只是猜测……您想用另一个 bean 更新一个 bean?

回答by Mohsen

Simply use your own copy method:

只需使用您自己的复制方法:

void copy(Object dest, Object source) throws IntrospectionException, IllegalArgumentException, IllegalAccessException,
        InvocationTargetException {
    BeanInfo beanInfo = Introspector.getBeanInfo(source.getClass());
    PropertyDescriptor[] pdList = beanInfo.getPropertyDescriptors();
    for (PropertyDescriptor pd : pdList) {
        Method writeMethod = null;
        Method readMethod = null;
        try {
            writeMethod = pd.getWriteMethod();
            readMethod = pd.getReadMethod();
        } catch (Exception e) {
        }

        if (readMethod == null || writeMethod == null) {
            continue;
        }

        Object val = readMethod.invoke(source);
        writeMethod.invoke(dest, val);
    }
}

回答by Arun B Chandrasekaran

I know the fact that this question is pretty old, but I thought the below answer may be useful for someone.

我知道这个问题已经很老了,但我认为以下答案可能对某人有用。

If you use Spring, you may try the below option.

如果您使用 Spring,您可以尝试以下选项。

import java.beans.PropertyDescriptor;
import java.util.HashSet;
import java.util.Set;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

/**
 * Helper class to extract property names from an object.
 * 
 * @Threadsafe
 * 
 * @author arun.bc
 * 
 */
public class PropertyUtil {

    /**
     * Gets the properties which have null values from the given object.
     * 
     * @param - source object
     * 
     * @return - String array of property names.
     */
    public static String[] getNullPropertiesString(Object source) {
        Set<String> emptyNames = getNullProperties(source);
        String[] result = new String[emptyNames.size()];

        return emptyNames.toArray(result);
    }


    /**
     * Gets the properties which have null values from the given object.
     * 
     * @param - source object
     * 
     * @return - Set<String> of property names.
     */
    public static Set<String> getNullProperties(Object source) {
        final BeanWrapper src = new BeanWrapperImpl(source);
        PropertyDescriptor[] pds = src.getPropertyDescriptors();

        Set<String> emptyNames = new HashSet<String>();
        for (PropertyDescriptor pd : pds) {
            Object srcValue = src.getPropertyValue(pd.getName());
            if (srcValue == null)
                emptyNames.add(pd.getName());
        }
        return emptyNames;
    }

    /**
     * Gets the properties which are not null from the given object.
     * 
     * @param - source object
     * 
     * @return - Set<String> array of property names.
     */
    public static Set<String> getNotNullProperties(Object source) {
        final BeanWrapper src = new BeanWrapperImpl(source);
        PropertyDescriptor[] pds = src.getPropertyDescriptors();

        Set<String> names = new HashSet<String>();
        for (PropertyDescriptor pd : pds) {
            Object srcValue = src.getPropertyValue(pd.getName());
            if (srcValue != null)
                names.add(pd.getName());
        }

        return names;
    }
}

Again you may use PropertyDescriptor and the Set from the above methods to modify the object.

同样,您可以使用上述方法中的 PropertyDescriptor 和 Set 来修改对象。

回答by BaiJiFeiLong

If your setter's return type is not void, BeanUtils of Apache will not work, spring can. So combine the two.

如果你的setter的返回类型不是void,Apache的BeanUtils就不行,spring可以。所以将两者结合起来。

package cn.corpro.bdrest.util;

import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.ConvertUtilsBean;
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.springframework.beans.BeanUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;

/**
 * Author: [email protected]
 * DateTime: 2016/10/20 10:17
 */
public class MyBeanUtils {

    public static void copyPropertiesNotNull(Object dest, Object orig) throws InvocationTargetException, IllegalAccessException {
        NullAwareBeanUtilsBean.getInstance().copyProperties(dest, orig);
    }

    private static class NullAwareBeanUtilsBean extends BeanUtilsBean {

        private static NullAwareBeanUtilsBean nullAwareBeanUtilsBean;

        NullAwareBeanUtilsBean() {
            super(new ConvertUtilsBean(), new PropertyUtilsBean() {
                @Override
                public PropertyDescriptor[] getPropertyDescriptors(Class<?> beanClass) {
                    return BeanUtils.getPropertyDescriptors(beanClass);
                }

                @Override
                public PropertyDescriptor getPropertyDescriptor(Object bean, String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
                    return BeanUtils.getPropertyDescriptor(bean.getClass(), name);
                }
            });
        }

        public static NullAwareBeanUtilsBean getInstance() {
            if (nullAwareBeanUtilsBean == null) {
                nullAwareBeanUtilsBean = new NullAwareBeanUtilsBean();
            }
            return nullAwareBeanUtilsBean;
        }

        @Override
        public void copyProperty(Object bean, String name, Object value) throws IllegalAccessException, InvocationTargetException {
            if (value == null) return;
            super.copyProperty(bean, name, value);
        }
    }
}

回答by Lorenzo Luconi Trombacchi

Using PropertyUtils (commons-beanutils)

使用 PropertyUtils (commons-beanutils)

for (Map.Entry<String, Object> e : PropertyUtils.describe(parent).entrySet()) {
         if (e.getValue() != null && !e.getKey().equals("class")) {
                PropertyUtils.setProperty(anotherParent, e.getKey(), e.getValue());
         }
}

in Java8:

在 Java8 中:

    PropertyUtils.describe(parent).entrySet().stream()
        .filter(e -> e.getValue() != null)
        .filter(e -> ! e.getKey().equals("class"))
        .forEach(e -> {
        try {
            PropertyUtils.setProperty(anotherParent, e.getKey(), e.getValue());
        } catch (Exception e) {
            // Error setting property ...;
        }
    });

回答by samairtimer

I landed here after many years finding a solution, used simple java reflection to achieve it. Hope it helps!

经过多年寻找解决方案,我来到这里,使用简单的java反射来实现它。希望能帮助到你!

public static void copyDiff(Product destination, Product source) throws  
             IllegalAccessException, NoSuchFieldException {
for (Field field : source.getClass().getDeclaredFields()) {
    field.setAccessible(true);
    String name = field.getName();
    Object value = field.get(source);

    //If it is a non null value copy to destination
    if (null != value) 
    {

         Field destField = destination.getClass().getDeclaredField(name);
         destField.setAccessible(true);

         destField.set(destination, value);
    }
    System.out.printf("Field name: %s, Field value: %s%n", name, value);
   }
}