BeanUtils
2019-10-08 20:51 Loull 阅读(389) 评论(0) 编辑 收藏 举报import org.apache.commons.lang.StringUtils; import org.springframework.beans.BeanWrapper; import org.springframework.beans.BeansException; import org.springframework.beans.FatalBeanException; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import java.beans.PropertyDescriptor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; import static org.springframework.beans.BeanUtils.getPropertyDescriptor; import static org.springframework.beans.BeanUtils.getPropertyDescriptors; public class BeanUtils { /** * List集合Bean转换 * * @param sourceList 被转换Bean的集合 * @param clazz 目标对象Class * @param <T> 目标对象类型 * @return 目标对象集合 */ public static <T> List<T> convertBeanList(List<?> sourceList, Class<T> clazz) { return sourceList.stream() .map(r -> convertBean(r, clazz)) .collect(Collectors.toList()); } /** * 单Bean转换 * * @param source 被转换对象 * @param clazz 目标对象Class * @param <T> 目标对象类型 * @return 目标对象 */ public static <T> T convertBean(Object source, Class<T> clazz) { if (null == source) { return null; } T bean = (T)org.springframework.beans.BeanUtils.instantiateClass(clazz); copyProperties(source, bean, true); return bean; } /** * 合并对象中属性到目标对象中 * * @param target 目标对象 * @param sources 源对象列表 * @throws BeansException */ public static void merge(Object target, Object... sources) throws BeansException { for (Object source : sources) { copyProperties(source, target, false); } } /** * 合并对象中属性到目标对象中 * * @param targetClass 目标对象 * @param sources 源对象列表 * @throws BeansException */ public static <T> T merge(Class<T> targetClass, Object... sources) throws BeansException { T target = (T)org.springframework.beans.BeanUtils.instantiateClass(targetClass); for (Object source : sources) { copyProperties(source, target, false); } return target; } /** * Copy the property values of the given source bean into the target bean. * <p>Note: The source and target classes do not have to match or even be derived * from each other, as long as the properties match. Any bean properties that the * source bean exposes but the target bean does not will silently be ignored. * <p>This is just a convenience method. For more complex transfer needs, * consider using a full BeanWrapper. * * @param source the source bean * @param target the target bean * @throws BeansException if the copying failed * @see BeanWrapper */ private static void copyProperties(Object source, Object target, boolean copyNull) throws BeansException { copyProperties(source, target, copyNull, null, (String[])null); } /** * Copy the property values of the given source bean into the given target bean. * <p>Note: The source and target classes do not have to match or even be derived * from each other, as long as the properties match. Any bean properties that the * source bean exposes but the target bean does not will silently be ignored. * * @param source the source bean * @param target the target bean * @param editable the class (or interface) to restrict property setting to * @param ignoreProperties array of property names to ignore * @throws BeansException if the copying failed * @see BeanWrapper */ @SuppressWarnings("unchecked") private static void copyProperties(Object source, Object target, boolean copyNull, Class<?> editable, String... ignoreProperties) throws BeansException { Assert.notNull(source, "Source must not be null"); Assert.notNull(target, "Target must not be null"); Class<?> actualEditable = target.getClass(); if (editable != null) { if (!editable.isInstance(target)) { throw new IllegalArgumentException("Target class [" + target.getClass().getName() + "] not assignable to Editable class [" + editable.getName() + "]"); } actualEditable = editable; } PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable); List<String> ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null); for (PropertyDescriptor targetPd : targetPds) { Method writeMethod = targetPd.getWriteMethod(); if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) { PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName()); if (sourcePd != null) { Method readMethod = sourcePd.getReadMethod(); if (readMethod != null) { //当类型可以直接转换时 if (ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) { try { if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) { readMethod.setAccessible(true); } Object value = readMethod.invoke(source); if (value == null && !copyNull) { continue; } if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) { writeMethod.setAccessible(true); } writeMethod.invoke(target, value); } catch (Throwable ex) { throw new FatalBeanException( "Could not copy property '" + targetPd.getName() + "' from source to target", ex); } } else { try { if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) { readMethod.setAccessible(true); } Object value = readMethod.invoke(source); if (value == null && !copyNull) { continue; } //扩展的枚举相关逻辑 if (Objects.equals(writeMethod.getParameterTypes()[0], String.class) && value instanceof Enum) { if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) { writeMethod.setAccessible(true); } Enum<?> enumValue = (Enum<?>)value; writeMethod.invoke(target, enumValue.name()); } else if (value instanceof String && writeMethod.getParameterTypes()[0].isEnum()) { if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) { writeMethod.setAccessible(true); } String stringValue = (String)value; if (StringUtils.isBlank(stringValue)) { continue; } Class<Enum> enumTargetType = (Class<Enum>)writeMethod.getParameterTypes()[0]; writeMethod.invoke(target, convertStringToEnum(enumTargetType, stringValue)); } } catch (Throwable ex) { throw new FatalBeanException( "Could not copy property '" + targetPd.getName() + "' from source to target", ex); } } } } } } } private static Enum convertStringToEnum(Class<Enum> clazz, String s) { if (Enum.class.isAssignableFrom(clazz)) { return Enum.valueOf(clazz, s); } return null; } }