Helper是为了将非null属性从对象复制到另一个? (JAVA)

时间:2009-08-19 18:13:09

标签: java helper

请参阅以下课程

public class Parent {

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

    // getters and setters   

}

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

Parent parent = new Parent();

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

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

这样的东西
SomeHelper.copyNonNullProperties(parent, anotherParent);

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

你知道这样的帮助吗?

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

的问候,

8 个答案:

答案 0 :(得分:81)

我认为你已经有了一个解决方案,因为你问过很多时间。但是,它没有标记为已解决,也许我可以帮助其他用户。

您是否尝试过定义BeanUtilsBean包的org.commons.beanutils的子类?实际上,BeanUtils使用此类,因此这是对dfa提出的解决方案的改进。

检查该类的source code,我认为您可以通过检查空值来覆盖copyProperty方法,如果值为null,则不执行任何操作。

这样的事情:

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

}

然后你可以实例化一个NullAwareBeanUtilsBean并用它来复制你的bean,例如:

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

答案 1 :(得分:3)

使用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());
         }
}
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 ...;
        }
    });

答案 2 :(得分:2)

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

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

答案 3 :(得分:2)

如果你的setter的返回类型不是void,那么Apache的BeanUtils就无法工作了。所以结合两者。

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: BaiJiFeiLong@gmail.com
 * 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);
        }
    }
}

答案 4 :(得分:1)

经过多年寻找解决方案后,我来到了这里,使用简单的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);
   }
}

答案 5 :(得分:0)

您可以使用Apache Common BeanUtils,更具体地说the copyProperties helper in BeanUtils class

 BeanUtils.copyProperties(parent, anotherParent);   

但是为什么你只想要复制非空属性?如果parent中的某个属性为null,只需复制它,你在anotherParent中也有空吗?

猜猜......你想用另一个bean更新bean吗?

答案 6 :(得分:0)

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

如果您使用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;
    }
}

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

答案 7 :(得分:0)

这是我的改编,用于复制非null属性,包括使用Spring BeanUtils忽略属性。

package com.blah;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import java.beans.PropertyDescriptor;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.Nonnull;

/**
 * brett created on 10/1/20.
 * <p>
 * Modified from: https://codippa.com/skip-null-properties-spring-beanutils/
 */
public final class NullAwareBeanUtils {

    private NullAwareBeanUtils() {}

    /**
     * Copies non-null properties from one object to another.
     *
     * @param source
     * @param destination
     * @param ignoreProperties
     */
    public static void copyNonNullProperties(Object source, Object destination, String... ignoreProperties) {
        final Set<String> ignoreAllProperties = new HashSet<>();
        ignoreAllProperties.addAll(getPropertyNamesWithNullValue(source));
        ignoreAllProperties.addAll(Arrays.asList(ignoreProperties));

        BeanUtils.copyProperties(source, destination, ignoreAllProperties.toArray(new String[]{}));
    }

    @Nonnull
    private static Set<String> getPropertyNamesWithNullValue(Object source) {
        final BeanWrapper sourceBeanWrapper = new BeanWrapperImpl(source);
        final java.beans.PropertyDescriptor[] propertyDescriptors = sourceBeanWrapper.getPropertyDescriptors();
        final Set<String> emptyNames = new HashSet();

        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
            // Check if value of this property is null then add it to the collection
            Object propertyValue = sourceBeanWrapper.getPropertyValue(propertyDescriptor.getName());
            if (propertyValue != null) continue;

            emptyNames.add(propertyDescriptor.getName());
        }

        return emptyNames;
    }
}