BeanUtils.java
package org.oxerr.commons.ws.rs.bean;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.InvalidPropertyException;
public final class BeanUtils {
private BeanUtils() {
}
public static <T> T patch(T dest, Object orig) {
if (dest == null || orig == null) {
return dest;
}
try {
NullAwareBeanUtilsBean.getInstance().copyProperties(dest, orig);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new IllegalArgumentException(e);
}
return dest;
}
public static <T> T patch(T dest, Object orig, String... properties) {
if (dest == null || orig == null) {
return dest;
}
final BeanWrapper destBeanWrapper = new BeanWrapperImpl(dest);
final BeanWrapper origBeanWrapper = new BeanWrapperImpl(orig);
for (final String property : properties) {
final Object value = origBeanWrapper.getPropertyValue(property);
if (value != null) {
destBeanWrapper.setPropertyValue(property, value);
}
}
return dest;
}
public static <T> T patchExclude(T dest, Object orig,
String... excludedProperties) {
if (dest == null || orig == null) {
return dest;
}
final List<String> excludedPropertyList = Arrays.asList(excludedProperties);
final BeanWrapper destBeanWrapper = new BeanWrapperImpl(dest);
final BeanWrapper origBeanWrapper = new BeanWrapperImpl(orig);
for (final PropertyDescriptor pd : destBeanWrapper.getPropertyDescriptors()) {
if (pd.getWriteMethod() != null && !excludedPropertyList.contains(pd.getName())) {
final Object value = origBeanWrapper.getPropertyValue(pd.getName());
if (value != null) {
destBeanWrapper.setPropertyValue(pd.getName(), value);
}
}
}
return dest;
}
public static <T> T patchExclude(T dest, Object orig,
Set<Class<? extends Annotation>> excludedAnnotationTypes) {
if (dest == null || orig == null) {
return dest;
}
final BeanWrapper destBeanWrapper = new BeanWrapperImpl(dest);
final BeanWrapper origBeanWrapper = new BeanWrapperImpl(orig);
for (final PropertyDescriptor pd : destBeanWrapper.getPropertyDescriptors()) {
if (pd.getWriteMethod() != null) {
final Set<Annotation> annotations = new HashSet<>();
annotations.addAll(Arrays.asList(pd.getReadMethod().getAnnotations()));
annotations.addAll(Arrays.asList(pd.getWriteMethod().getAnnotations()));
try {
Field field = dest.getClass().getDeclaredField(pd.getName());
annotations.addAll(Arrays.asList(field.getAnnotations()));
} catch (NoSuchFieldException | SecurityException e) {
// ignore
}
final List<Class<? extends Annotation>> annotationTypes = annotations
.stream().map(Annotation::annotationType)
.collect(Collectors.toList());
annotationTypes.retainAll(excludedAnnotationTypes);
if (annotationTypes.isEmpty()) {
setPropertyValue(destBeanWrapper, origBeanWrapper, pd);
}
}
}
return dest;
}
private static void setPropertyValue(
final BeanWrapper destBeanWrapper,
final BeanWrapper origBeanWrapper,
final PropertyDescriptor pd
) {
try {
final Object value = origBeanWrapper.getPropertyValue(pd.getName());
if (value != null) {
destBeanWrapper.setPropertyValue(pd.getName(), value);
}
} catch (InvalidPropertyException e) {
if (!isCausedByIgnorableException(e)) {
throw e;
}
}
}
private static boolean isCausedByIgnorableException(InvalidPropertyException e) {
if (!(e.getCause() instanceof InvocationTargetException)) {
return false;
}
final Throwable cause = e.getCause().getCause();
if (cause == null) {
return false;
} else if (cause instanceof NoSuchFieldException) {
return true;
} else if (cause instanceof SecurityException) {
return true;
}
return false;
}
@SuppressWarnings("unchecked")
public static <T> T patchExclude(T dest, Object orig,
Class<?>... excludedAnnotationTypes) {
patchExclude(dest, orig,
Arrays.asList(excludedAnnotationTypes).stream()
.map(e -> (Class<? extends Annotation>) e)
.collect(Collectors.toSet()));
return dest;
}
public static <T> T copyProperties(T dest, Object orig, String... properties) {
if (dest == null || orig == null) {
return dest;
}
final BeanWrapper destBeanWrapper = new BeanWrapperImpl(dest);
final BeanWrapper origBeanWrapper = new BeanWrapperImpl(orig);
for (final String property : properties) {
final Object value = origBeanWrapper.getPropertyValue(property);
destBeanWrapper.setPropertyValue(property, value);
}
return dest;
}
}