1

I'm using Spring but not that familiar with all its capabilities. Looking for a good way to copy fields from one Java object instance to another. I've seen How to copy properties from one Java bean to another? but what i'm looking for is more specific, so here are the details:

Suppose I have two instances of some class P, source & target, which have getters and setters a,b,c,d and 20 others. I want to copy the properties of of source into target, but only for all properties in a list of property names. It does not matter what is the value of any property in either source or target.
In other words, if the list is {"a", "b"}
then i just want the following to happen:

P source;
P target;
List<string> properties; 

//source, target are populated. properties is {"a", "b"}  
//Now I need some Spring (SpEL?) trick to do the equivalent of:
target.setA(source.getA());
target.setB(source.getB());
inor
  • 2,781
  • 2
  • 32
  • 42
  • Possible duplicate of https://stackoverflow.com/questions/5079458/copy-specific-fields-by-using-beanutils-copyproperties? – leonz Sep 12 '17 at 11:21

2 Answers2

3

I don't think SpEL requires here, it can be solved with BeanUtils.copyProperties(Object, Object, String...). According your example, if your class has properties 'a','b','c' and you want to copy only first two, you can call it like so

BeanUtils.copyProperties(source, target, "c");

Hope it helps!

Sergey Prokofiev
  • 1,815
  • 1
  • 12
  • 21
  • Well, is there an easy way in Spring to get a List of all the properties of a class? because I will need that list and I will need to remove from it all the properties in my list before i can call copyProperties – inor Sep 12 '17 at 11:34
  • @inor, sure, you just need a little bit of dark magic of reflection `List fieldNames = Arrays.asList(P.class.getDeclaredFields()).stream().map(Field::getName).collect(Collectors.toList());` – Sergey Prokofiev Sep 12 '17 at 12:59
  • Hi Sergey. Thanks for the great answer. I learned from it that i need to catch up on dark magic. I up-ticked your answer but I'm going to give @leonz the check mark as his answer seems more efficient as it does not require traversal of all the fields – inor Sep 14 '17 at 10:02
  • @inor, it's ok! I'm glad that community helped you to solve this. – Sergey Prokofiev Sep 14 '17 at 11:07
3

Using Java Reflection:

Field[] fields = source.getClass().getDeclaredFields();

for (Field f: fields) {
    if (properties.contains(f.getName())) {

        f.setAccessible(true);

        f.set(destination, f.get(source));
    }
}

Here are some tutorials on Reflection:

http://www.oracle.com/technetwork/articles/java/javareflection-1536171.html

http://tutorials.jenkov.com/java-reflection/index.html

Be careful though, Reflection has specific use cases.


Using Spring BeanWrapper:

BeanWrapper srcWrap = PropertyAccessorFactory.forBeanPropertyAccess(source);
BeanWrapper destWrap = PropertyAccessorFactory.forBeanPropertyAccess(destination);

properties.forEach(p -> destWrap.setPropertyValue(p, srcWrap.getPropertyValue(p)));

Credit for Spring BeanWrapper example goes to: https://stackoverflow.com/a/5079864/6510058

leonz
  • 1,107
  • 2
  • 10
  • 32
  • Thanks Leonz, for the very comprehensive answer. Since I'm using Spring, I used your BeanWrapper solution. I had to make a trivial change to the last line since I'm restricted to Java 7 at the moment. Not bothring posting it. Perhaps you should... – inor Sep 14 '17 at 10:09