如何将属性从一个Java bean复制到另一个?

时间:2009-05-07 15:43:47

标签: java javabeans

我有一个简单的Java POJO,我会将属性复制到同一个POJO类的另一个实例。

我知道我可以使用BeanUtils.copyProperties()来做到这一点,但我想避免使用第三方库。

那么,如何以简单,恰当和安全的方式做到这一点?

顺便说一下,我正在使用Java 6.

8 个答案:

答案 0 :(得分:12)

我想如果你看一下BeanUtils的源代码,它会告诉你如何在不使用BeanUtils的情况下做到这一点。

如果您只是想创建POJO的副本(与将属性从一个POJO复制到另一个POJO不完全相同),您可以更改源bean以实现clone()方法和Cloneable接口。 / p>

答案 1 :(得分:11)

我在为Google App Engine开发应用时遇到了同样的问题,由于公共日志限制,我无法使用BeanUtils。无论如何,我提出了这个解决方案并且对我来说工作得很好。

public static void copyProperties(Object fromObj, Object toObj) {
    Class<? extends Object> fromClass = fromObj.getClass();
    Class<? extends Object> toClass = toObj.getClass();

    try {
        BeanInfo fromBean = Introspector.getBeanInfo(fromClass);
        BeanInfo toBean = Introspector.getBeanInfo(toClass);

        PropertyDescriptor[] toPd = toBean.getPropertyDescriptors();
        List<PropertyDescriptor> fromPd = Arrays.asList(fromBean
                .getPropertyDescriptors());

        for (PropertyDescriptor propertyDescriptor : toPd) {
            propertyDescriptor.getDisplayName();
            PropertyDescriptor pd = fromPd.get(fromPd
                    .indexOf(propertyDescriptor));
            if (pd.getDisplayName().equals(
                    propertyDescriptor.getDisplayName())
                    && !pd.getDisplayName().equals("class")) {
                 if(propertyDescriptor.getWriteMethod() != null)                
                         propertyDescriptor.getWriteMethod().invoke(toObj, pd.getReadMethod().invoke(fromObj, null));
            }

        }
    } catch (IntrospectionException e) {
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
}

非常欢迎任何增强或推荐。

答案 2 :(得分:3)

另一个替代方法是MapStruct,它在构建时生成映射代码,从而产生类型安全的映射,在运行时不需要任何依赖(免责声明:我是MapStruct的作者)。

答案 3 :(得分:3)

嘿朋友们只需使用我创建的ReflectionUtil类将一个bean值复制到另一个类似的bean。 该类还将复制Collections对象。

https://github.com/vijayshegokar/Java/blob/master/Utility/src/common/util/reflection/ReflectionUtil.java

注意:此bean必须具有类似的变量名称,并且具有getter和setter。

现在增加了更多功能。您还可以将一个实体数据复制到其bean。 如果一个实体中有另一个实体,那么您可以将内部实体的运行时更改的map选项传递给其相关的bean。

例如

ParentEntity parentEntityObject = getParentDataFromDB();
Map<Class<?>, Class<?>> map = new HashMap<Class<?>, Class<?>>();
map.put(InnerBean1.class, InnerEntity1.class);
map.put(InnerBean2.class, InnerEntity2.class);
ParentBean parent = ReflectionUtil.copy(ParentBean.class, parentEntityObject, map);

当您的实体包含关系时,此案例非常有用。

答案 4 :(得分:2)

查看JavaBeans API,特别是Introspector课程。您可以将BeanInfo元数据用于getset属性。如果你还没有阅读JavaBeans specification,最好先阅读。它也有助于熟悉reflection API

答案 5 :(得分:1)

没有简单的方法可以做到。 Introspector和Java bean库是单片的 - BeanUtils是一个简单的包装器并且运行良好。没有库只是为了没有库通常是一个坏主意 - 这是一个共同的原因 - Java应该存在的常见功能,但不是。

答案 6 :(得分:1)

我遇到了Introspector.getBeanInfo没有返回所有属性的问题,所以我最终实现了字段副本而不是属性副本。

public static <T> void copyFields(T target, T source) throws Exception{
    Class<?> clazz = source.getClass();

    for (Field field : clazz.getFields()) {
        Object value = field.get(source);
        field.set(target, value);
    }
}

答案 7 :(得分:0)

您可以使用 Java Reflection API 来实现它。

public static <T> void copy(T target, T source) throws Exception {
    Class<?> clazz = source.getClass();

    for (Field field : clazz.getDeclaredFields()) {
        if (Modifier.isPrivate(field.getModifiers()))
            field.setAccessible(true);
        Object value = field.get(source);
        field.set(target, value);
    }
}