14

I have a simple Java POJO that I would copy properties to another instance of same POJO class.

I know I can do that with BeanUtils.copyProperties() but I would like to avoid use of a third-party library.

So, how to do that simply, the proper and safer way ?

By the way, I'm using Java 6.

paulgreg
  • 18,493
  • 18
  • 46
  • 56
  • 8
    Um, BeanUtils.copyProperties() *is* the proper way. It's in that library because there's no easy way to do it otherwise. If you really don't want to use BeanUtils, then download the sourcecode for it, and copy the method. – skaffman May 07 '09 at 15:47
  • 1
    skaffman - I didn't see your comment when I posted my answer, sorry. But as you can see I completely agree with you :) – MetroidFan2002 May 07 '09 at 16:53
  • 1
    Note that Spring also includes a [BeanUtils.copyProperties](http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/beans/BeanUtils.html) method which may be more convenient if you're already using Spring. – pimlottc Oct 17 '12 at 20:09

8 Answers8

12

I had the same problem when developing an app for Google App Engine, where I couldn't use BeanUtils due to commons Logging restrictions. Anyway, I came up with this solution and worked just fine for me.

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

Any enhancements or recomendations are really welcome.

Efthymis
  • 1,326
  • 11
  • 13
  • 1
    Thanks, you helped me with this question: http://stackoverflow.com/questions/8384814/when-can-propertyutils-copyproperties-fail-silently I suggest you add support for read-only properties by checking if `propertyDescriptor.getWriteMethod()` returns null. – ripper234 Dec 05 '11 at 13:03
  • 1
    Thanks for the recommendation. I edited my answer to add support for read-only properties. – Efthymis Dec 08 '11 at 08:14
12

I guess if you look at the source code of BeanUtils, it will show you how to do this without actually using BeanUtils.

If you simply want to create a copy of a POJO (not quite the same thing as copying the properties from one POJO to another), you could change the source bean to implement the clone() method and the Cloneable interface.

Dónal
  • 185,044
  • 174
  • 569
  • 824
  • 1
    If all of the properties are backed by fields, making it cloneable should do nicely, and is very efficient. However, note that it's a shallow copy... – Scott Stanchfield May 08 '09 at 14:39
  • 1
    It's a shallow copy if you merely implement Cloneable and overrid clone() to make it public and call the parent implementation. But of course, you could implement clone() to do anything, including creating a deep copy. Check out 'Effective Java' for further details about clone(). – Dónal May 08 '09 at 20:10
3

Another alternative is MapStruct which generates mapping code at build time, resulting in type-safe mappings which don't require any dependencies at runtime (Disclaimer: I'm the author of MapStruct).

Gunnar
  • 18,095
  • 1
  • 53
  • 73
3

Hey friends just use my created ReflectionUtil class for copy one bean values to another similar bean. This class will also copy Collections object.

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

Note: This bean must have similar variables name with type and have getter and setters for them.

Now more functionalities are added. You can also copy one entity data to its bean. If one entity has another entity in it then you can pass map option for runtime change of inner entity to its related bean.

Eg.

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

This case is very useful when your Entities contains relationship.

Vijay Shegokar
  • 2,492
  • 1
  • 20
  • 30
2

Have a look at the JavaBeans API, in particular the Introspector class. You can use the BeanInfo metadata to get and set properties. It is a good idea to read up on the JavaBeans specification if you haven't already. It also helps to have a passing familiarity with the reflection API.

McDowell
  • 107,573
  • 31
  • 204
  • 267
  • Good advice, but it's probably fair to assume the end result of all that will probably be an inferior implementation of BeanUtils.copyProperties() – Dónal May 07 '09 at 16:01
  • That's a fair comment, but it never hurts to know what's going on. – McDowell May 07 '09 at 16:10
  • Thx. I'm new with Java 6 so I hoped there will be a way to do that more easily than on previous versions. But I will definitely take a look on your links. – paulgreg May 07 '09 at 16:19
1

There is no simple way to do it. Introspector and the Java beans libraries are monolithic - BeanUtils is a simple wrapper around this and works well. Not having libraries just to not have libraries is a bad idea in general - there's a reason it's commons to begin with - common functionality that should exist with Java, but doesn't.

MetroidFan2002
  • 29,217
  • 16
  • 62
  • 80
1

I ran into some problems with Introspector.getBeanInfo not returning all the properties, so I ended up implementing a field copy instead of property copy.

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);
    }
}
ripper234
  • 222,824
  • 274
  • 634
  • 905
0

You can achieve it using 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);
    }
}
Piyush Chaudhari
  • 962
  • 3
  • 19
  • 41