【问题标题】:How to copy properties from one Java bean to another?如何将属性从一个 Java bean 复制到另一个?
【发布时间】:2009-05-07 15:43:47
【问题描述】:

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

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

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

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

【问题讨论】:

  • 嗯,BeanUtils.copyProperties() 正确的方法。它在那个库中,因为没有简单的方法可以做到这一点。如果你真的不想用 BeanUtils,那就下载它的源代码,然后复制方法。
  • skaffman - 我发布答案时没有看到您的评论,抱歉。但正如你所看到的,我完全同意你的看法:)
  • 请注意,Spring 还包括一个 BeanUtils.copyProperties 方法,如果您已经在使用 Spring,它可能会更方便。

标签: java javabeans


【解决方案1】:

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

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

【讨论】:

  • 如果所有属性都由字段支持,使其可克隆应该做得很好,并且非常有效。但是,请注意,这是一个浅拷贝...
  • 如果只实现 Cloneable 并覆盖 clone() 使其公开并调用父实现,这是一个浅拷贝。但是当然,你可以实现 clone() 来做任何事情,包括创建一个深拷贝。有关 clone() 的更多详细信息,请查看“Effective Java”。
【解决方案2】:

我在为 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();
    }
}

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

【讨论】:

  • 谢谢,你帮我解决了这个问题:stackoverflow.com/questions/8384814/… 我建议你通过检查propertyDescriptor.getWriteMethod() 是否返回 null 来添加对只读属性的支持。
  • 感谢您的推荐。我编辑了答案以添加对只读属性的支持。
【解决方案3】:

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

【讨论】:

    【解决方案4】:

    嘿,朋友们只需使用我创建的 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);
    

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

    【讨论】:

      【解决方案5】:

      查看JavaBeans API,尤其是Introspector 类。您可以将 BeanInfo 元数据用于 getset 属性。如果您还没有阅读JavaBeans specification,这是一个好主意。熟悉reflection API 也很有帮助。

      【讨论】:

      • 好建议,但可以公平地假设所有这些的最终结果可能是 BeanUtils.copyProperties() 的较差实现
      • 这是一个中肯的评论,但知道发生了什么永远不会有坏处。
      • 谢谢。我是 Java 6 的新手,所以我希望有一种方法比以前的版本更容易做到这一点。但我一定会看看你的链接。
      【解决方案6】:

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

      【讨论】:

        【解决方案7】:

        我遇到了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);
            }
        }
        

        【讨论】:

          【解决方案8】:

          您可以使用 Java 反射 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);
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-11-13
            • 1970-01-01
            • 2014-02-27
            • 2019-01-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-05-31
            相关资源
            最近更新 更多