CopyUtil(java复合bean的copy)

您所在的位置:网站首页 beanutils工具类中copy方法 CopyUtil(java复合bean的copy)

CopyUtil(java复合bean的copy)

2023-09-26 07:50| 来源: 网络整理| 查看: 265

诞生由来

之前项目里就经常有bean之间的属性copy,一直都是用spring自带的工具类来解决,方法如下:

org.springframework.beans.BeanUtils#copyProperties(java.lang.Object, java.lang.Object);

该方法只能对一个bean中普通属性字段进行copy,如果这个bean中有其他的bean,即bean中bean,就需要将其值取出,单独对这个子bean进行copy,然后set进父bean,这种copy如果在bean层次少的时候还无所谓,如果在bean的层次比较深的时候,就会发现很是繁琐了,最近遇到的项目里面有bean和bo的转换,其深度就有四五层,所以如果能想出一个新的工具类,能够一次性copy其bean中bena肯定最好不过了。

以前用的简单包装工具类 满足单层bean的copy。满足单层bean集合的copy。 public class CopyUtil { @SuppressWarnings("all") public static T copy(Object fromBean, Class clz) throws InstantiationException, IllegalAccessException { if (fromBean == null || clz == null) { return null; } T result = clz.newInstance(); BeanUtils.copyProperties(fromBean, result); return result; } public static List copy(Collection fromBeans, Class cls) throws InstantiationException, IllegalAccessException { if (CollectionUtils.isEmpty(fromBeans) || null == cls) { return null; } List list = new ArrayList(); for (Object fromBean : fromBeans) { T t = copy(fromBean, cls); if (t != null) { list.add(t); } } return list; } } 通过反射写出的新的一套工具类 满足单层bean的copy。满足单层bean集合的copy。满足多层bean的复合copy。 思路 获取fromBean中的属性字段,如果toBean中也有其属性字段,则继续下一步。反射执行get/is获取其属性field,得到属性类型type,属性值fieldValue。如果type是普通类型,则直接反射执行set方法将值写入toBean。如果type是List集合类型,调用getFieldIfList获取对应toBean中的该属性值toList: 获取这个List类型属性里面包裹的属性类型type_child。如果type_child仍是List集合类型,递归调用getFieldIfList去掉List外壳,并将值add进其父List。如果type_child不是集合类型,通过Class.forName获取其class: 如果type_child是一般类型,直接将传进来的list值add进toList返回。如果type_child是child_bean类型,遍历传进来的list,对其每个值又重新调用copy方法set进new出来的新child_bean实例中,返回。 如果type是Map类型,暂不考虑。如果type不是以上类型(忽略考虑了java里面或者其他类里面定义的内置bean类型),判定为bean中bean类型: 反射获取toBean中对应字段的class:Class newToClass = toClass.getDeclaredField(field.getName()).getType(); Object newToBean = newToClass.newInstance(); 再次调用copy方法将fieldValue写入newToBean,然后执行set方法将newToBean写入toBean。 最终返回toBean即目标结果。 判断是否是普通字段属性 /** * @Author ifdream * @Description 返回该字段的类型是否是普通类型 * @Date 10:14 2019/9/21 * @Param [clazz] * @return boolean **/ private static boolean isNormalField(Class clazz) { return clazz == int.class || clazz == String.class || clazz == float.class || clazz == double.class || clazz == char.class || clazz == byte.class || clazz == short.class || clazz == Date.class || clazz == boolean.class || clazz == Integer.class || clazz == Float.class || clazz == Double.class || clazz == Character.class || clazz == Byte.class || clazz == Short.class || clazz == Boolean.class || clazz == long.class || clazz == Long.class; } 整体工具类 /** * @Auther: ifdream * @Date: 2019/9/21 09:39 * @Description: */ public class CopyUtil { private final static String LIST_STR = "java.util.List"; private final static String SERIAL_FIELD_STR = "serialVersionUID"; private final static int LIST_STR_LEN = "java.util.List".length(); @SuppressWarnings("all") public static T copy(Object fromBean, Class clz) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException, ClassNotFoundException, InstantiationException { if (fromBean == null || clz == null) { return null; } if (isNormalField(clz)) { if (fromBean.getClass() == clz) { // 类型一致 return (T) fromBean; } throw new IllegalArgumentException("this fromBean is not " + clz + " type"); } return copy(fromBean, clz.newInstance()); } public static List copy(Collection fromBeans, Class cls) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException, ClassNotFoundException, InstantiationException { if (CollectionUtils.isEmpty(fromBeans) || null == cls) { return null; } List list = new ArrayList(); for (Object fromBean : fromBeans) { T t = copy(fromBean, cls); if (t != null) { list.add(t); } } return list; } /** * @Author ifdream * @Description 要求 bean 中对应字段的属性名必须一致,普通类型字段要求字段类型一致 * @Date 10:12 2019/9/21 * @Param [fromBean, toBean] 从 fromBean 复制到 toBean * @return E **/ @SuppressWarnings("all") public static E copy(Object fromBean, E toBean) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException, ClassNotFoundException, InstantiationException { if (fromBean == null || toBean == null) return null; Class fromClass = fromBean.getClass(); Class toClass = toBean.getClass(); for (Field field : fromClass.getDeclaredFields()) { if (field.getName().equals(SERIAL_FIELD_STR)) { // 序列化字段,忽略 continue; } try { if (toClass.getDeclaredField(field.getName()) == null) { // toClass 中没有该属性字段 continue; } if (isNormalField(field.getType()) && toClass.getDeclaredField(field.getName()).getType() != field.getType()) { // 属性是普通字段,且二者对应属性字段的类型不同 continue; } } catch (NoSuchFieldException e) { continue; } String getMethodName = "get" + StringUtils.capitalize(field.getName()); String setMethodName = "set" + StringUtils.capitalize(field.getName()); String isMethodName = "is" + StringUtils.capitalize(field.getName()); Object fieldValue; if (field.getType() == boolean.class || field.getType() == Boolean.class) { // boolean 类型 fieldValue = fromClass.getDeclaredMethod(isMethodName).invoke(fromBean); } else { fieldValue = fromClass.getDeclaredMethod(getMethodName).invoke(fromBean); } if (null == fieldValue) { // fromBean 无此属性值 continue; } if (isNormalField(field.getType())) { Method method = toClass.getDeclaredMethod(setMethodName, field.getType()); method.invoke(toBean, fieldValue); } else if (field.getType() == List.class) { List list = (List) fieldValue; String str = toClass.getDeclaredField(field.getName()).getGenericType().toString(); List toList = getFieldIfList(list, str); Method method = toClass.getDeclaredMethod(setMethodName, List.class); method.invoke(toBean, toList); } else if (field.getType() == Map.class){ // TODO Map 暂不处理 } else { // bean 中 bean Class newToClass = toClass.getDeclaredField(field.getName()).getType(); Object newToBean = newToClass.newInstance(); copy(fieldValue, newToBean); Method method = toClass.getDeclaredMethod(setMethodName, newToClass); method.invoke(toBean, newToBean); } } return toBean; } /** * @Author ifdream * @Description 获取当源属性类型是 {@link List} 时的目标属性值 * @Date 12:13 2019/9/22 * @Param [list, toBeanClassStr] * @return java.util.List **/ @SuppressWarnings("all") private static List getFieldIfList(List list, String toBeanClassStr) throws IllegalAccessException, InstantiationException, ClassNotFoundException, NoSuchMethodException, NoSuchFieldException, InvocationTargetException { String newBeanClassStr = toBeanClassStr.substring(LIST_STR_LEN + 1, toBeanClassStr.length() - 1); if (newBeanClassStr.contains(LIST_STR)) { List result = new ArrayList(); for (T t : list) { // 递归去掉 list 外壳 List toT = getFieldIfList((List) t, newBeanClassStr); result.add(toT); } return result; } Class toBeanClass = Class.forName(newBeanClassStr); List toList = new ArrayList(); if (isNormalField(toBeanClass)) { // 说明 list 里面的元素是一般属性字段 toList.addAll(list); } else { for (T t : list) { Object toT = copy(t, toBeanClass.newInstance()); toList.add(toT); } } return toList; } /** * @Author ifdream * @Description 返回该字段的类型是否是普通类型 * @Date 10:14 2019/9/21 * @Param [clazz] * @return boolean **/ private static boolean isNormalField(Class clazz) { return clazz == int.class || clazz == String.class || clazz == float.class || clazz == double.class || clazz == char.class || clazz == byte.class || clazz == short.class || clazz == Date.class || clazz == boolean.class || clazz == Integer.class || clazz == Float.class || clazz == Double.class || clazz == Character.class || clazz == Byte.class || clazz == Short.class || clazz == Boolean.class || clazz == long.class || clazz == Long.class; } } 简单测试 @Data public class Bean1 { private String name; private List list; private Bean1_2 testBean; private List aList; private List bList; private List cList; } @Data public class Bean2 { private String name; private List list; private Bean2_2 testBean; private List aList; private List bList; private List cList; } ... 里面都是一些简单的bean,就不一一展开

main方法简单set值进行copy,打印对比测试:

Bean1(name=aaa, list=[Bean1_1(name=name0, id=6, testBean=[Bean1_1_1(age=17, birthday=Sun Sep 22 14:11:47 CST 2019), Bean1_1_1(age=16, birthday=Sun Sep 22 14:11:47 CST 2019)], success=true), Bean1_1(name=name1, id=0, testBean=[Bean1_1_1(age=15, birthday=Sun Sep 22 14:11:47 CST 2019), Bean1_1_1(age=15, birthday=Sun Sep 22 14:11:47 CST 2019)], success=true)], testBean=Bean1_2(test=100), aList=[a1, a2], bList=[[1, 2], [1, 2]], cList=[[Bean1_3(id=10), Bean1_3(id=10), Bean1_3(id=10)], [Bean1_3(id=11), Bean1_3(id=11), Bean1_3(id=11)]]) Bean2(name=aaa, list=[Bean2_1(name=name0, id=6, testBean=[Bean2_1_1(age=17, birthday=Sun Sep 22 14:11:47 CST 2019), Bean2_1_1(age=16, birthday=Sun Sep 22 14:11:47 CST 2019)], success=true), Bean2_1(name=name1, id=0, testBean=[Bean2_1_1(age=15, birthday=Sun Sep 22 14:11:47 CST 2019), Bean2_1_1(age=15, birthday=Sun Sep 22 14:11:47 CST 2019)], success=true)], testBean=Bean2_2(test=100), aList=[a1, a2], bList=[[1, 2], [1, 2]], cList=[[Bean2_3(id=10), Bean2_3(id=10), Bean2_3(id=10)], [Bean2_3(id=11), Bean2_3(id=11), Bean2_3(id=11)]]) 结语

以上为博主应需写出的工具类,肯定不尽完美,读者发现有问题,可以提出来,博主很乐意一直完善该工具类~

如果您看到了这里,欢迎和我沟通交流!              一个95后码农

个人博客:fy-blog



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3