Solution:
public <M> void merge(M target, M destination) throws Exception {
BeanInfo beanInfo = Introspector.getBeanInfo(target.getClass());
// Iterate over all the attributes
for (PropertyDescriptor descriptor : beanInfo.getPropertyDescriptors()) {
// Only copy writable attributes
if (descriptor.getWriteMethod() != null) {
Object originalValue = descriptor.getReadMethod()
.invoke(target);
// Only copy values values where the destination values is null
if (originalValue == null) {
Object defaultValue = descriptor.getReadMethod().invoke(
destination);
descriptor.getWriteMethod().invoke(target, defaultValue);
}
}
}
}
Test code:
@Test
public void testMerge() throws Exception {
Person templatePerson = new Person("Template", 20);
Person targetPerson = new Person("Johan", null);
merge(targetPerson, templatePerson);
assertEquals("Johan", targetPerson.getName());
assertEquals(20, targetPerson.getAge());
}
private static class Person {
private String name;
private Integer age;
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getAge() {
return age;
}
}
Hi Lennart,
ReplyDeletenice post however the topic could get much more complicated when
(1) a target object that holds a property that is a List - the source object holds a List as well however has 3 more items in this list. In this case one would expect to get the additional values of this list merged as well - however this will not happen in the example above.
(2) you want to do a "deep merge" when your Bean contains other Beans which should get merged as well.
Cheers,
Walt