14

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

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

那么,如何简单、正确、安全地做到这一点呢?

顺便说一句,我使用的是 Java 6。

4

8 回答 8

12

我想如果您查看 BeanUtils 的源代码,它将向您展示如何在不实际使用 BeanUtils 的情况下执行此操作。

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

于 2009-05-07T15:48:30.343 回答
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();
    }
}

任何改进或建议都非常受欢迎。

于 2011-10-21T06:41:32.140 回答
3

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

于 2013-07-09T16:54:46.447 回答
3

嘿,朋友们只需使用我创建的 ReflectionUtil 类将一个 bean 值复制到另一个类似的 bean。此类还将复制 Collections 对象。https://github.com/vijayshegokar/Java/blob/master/Utility/src/common/util/reflection/ReflectionUtil.java

注意:此 bean 必须具有与类型相似的变量名称,并且具有用于它们的 getter 和 setter。

现在添加了更多功能。您还可以将一个实体数据复制到其 bean。如果一个实体中有另一个实体,那么您可以将内部实体的运行时更改的映射选项传递给它的相关 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);

当您的实体包含关系时,这种情况非常有用。

于 2014-02-07T10:02:09.570 回答
2

查看JavaBeans API,尤其是Introspector类。您可以使用 BeanInfo 元数据来获取设置属性。如果您还没有阅读JavaBeans 规范,最好阅读一下。熟悉反射 API也很有帮助。

于 2009-05-07T15:58:56.467 回答
1

没有简单方法可以做到这一点。Introspector 和 Java bean 库是一体的 - BeanUtils 是一个简单的包装器,并且运行良好。没有库只是为了没有库一般来说是个坏主意——这是有原因的,从一开始就是公共的——Java应该存在的公共功能,但没有。

于 2009-05-07T16:31:50.677 回答
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);
    }
}
于 2011-12-05T13:50:53.120 回答
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);
    }
}
于 2017-07-10T14:02:50.837 回答