Copy non-null properties from one object to another using BeanUtils or similar
I ended up using Spring BeanUtils library. Here is my working method:
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import java.lang.reflect.Field;
import java.util.Collection;
public class MyBeansUtil<T> {
public T copyNonNullProperties(T target, T in) {
if (in == null || target == null || target.getClass() != in.getClass()) return null;
final BeanWrapper src = new BeanWrapperImpl(in);
final BeanWrapper trg = new BeanWrapperImpl(target);
for (final Field property : target.getClass().getDeclaredFields()) {
Object providedObject = src.getPropertyValue(property.getName());
if (providedObject != null && !(providedObject instanceof Collection<?>)) {
trg.setPropertyValue(
property.getName(),
providedObject);
}
}
return target;
}
}
It works fine, but notice that it ignores fields that are collections. That's on purpose, I handle them separately.
You can create your own method to copy properties while ignoring null values.
public static String[] getNullPropertyNames (Object source) {
final BeanWrapper src = new BeanWrapperImpl(source);
java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();
Set<String> emptyNames = new HashSet<String>();
for(java.beans.PropertyDescriptor pd : pds) {
Object srcValue = src.getPropertyValue(pd.getName());
if (srcValue == null) emptyNames.add(pd.getName());
}
String[] result = new String[emptyNames.size()];
return emptyNames.toArray(result);
}
// then use Spring BeanUtils to copy and ignore null
public static void myCopyProperties(Object src, Object target) {
BeanUtils.copyProperties(src, target, getNullPropertyNames(src))
}
Using BeanUtils and java8 we can achieve this:
BeanUtils.copyProperties(Object_source, Object_target, getNullPropertyNames(Object_source));
private String[] getNullPropertyNames(Object source) {
final BeanWrapper wrappedSource = new BeanWrapperImpl(source);
return Stream.of(wrappedSource.getPropertyDescriptors()).map(FeatureDescriptor::getName)
.filter(propertyName -> wrappedSource.getPropertyValue(propertyName) == null).toArray(String[]::new);
}