重载copyProperties,使其支持Map类型

    最近,项目组要用到一个功能,就是用BeanUtils.copyProperties复制一个Map里的属性值到另外一个对象。

    BeanUtils和PropertyUtils类是许多开源框架中频繁使用的两个工具,它们都能实现将一个类中的属性拷贝到另一个类中,这个功能甚至是spring实现依赖注入的基础。研究一下apache的comon包中如何实现这个两个工具,可以发现它们都是使用java.lang.reflect和java.beans这两个包下的几个类来实现的。

    但是BeanUtils.copyProperties只支持两个对象之间的复制,其原理:是利用反射读取到第一个对象(源类)的所有属性,然后对这些属性集合进行for循环,再在for循环里面判断这些属性是否有set方法,有则再对第二个对象(目标类)进行循环取出属性一一对比,相等则调用目标类的set方法得到源类的get方法得到的值。

    改后主要就是两点:第一:源类(Map类型)的Key作为属性和目标类的属性对比,相等则取出此Key的Value赋给目标类(当然还是用目标类此属性的set方法)。注意:如果是页面得到的getParameterMap()这样的Map,其值是一个数组,一般只需要取第0项就可以了。

源代码:

  1. /** 实现将源类属性拷贝到目标类中
  2.        * @param source 
  3.        * @param target
  4.        */
  5.     public static void copyProperties(Object source, Object target) {
  6.         try {
  7.             // 获取目标类的属性信息
  8.             BeanInfo targetbean = Introspector.getBeanInfo(target.getClass());
  9.             PropertyDescriptor[] propertyDescriptors = targetbean
  10.                     .getPropertyDescriptors();
  11.             // 对每个目标类的属性查找set方法,并进行处理
  12.             for (int i = 0; i < propertyDescriptors.length; i++) {
  13.                 PropertyDescriptor pro = propertyDescriptors[i];
  14.                 Method wm = pro.getWriteMethod();
  15.                 if (wm != null) {// 当目标类的属性具有set方法时,查找源类中是否有相同属性的get方法
  16.                     BeanInfo sourceBean = Introspector.getBeanInfo(source.getClass());
  17.                     PropertyDescriptor[] sourcepds = sourceBean.getPropertyDescriptors();
  18.                     for (int j = 0; j < sourcepds.length; j++) {
  19.                         if (sourcepds[j].getName().equals(pro.getName())) { // 匹配
  20.                             Method rm = sourcepds[j].getReadMethod();
  21.                             // 如果方法不可访问(get方法是私有的或不可达),则抛出SecurityException
  22.                             if (!Modifier.isPublic(rm.getDeclaringClass().getModifiers())) {
  23.                                 rm.setAccessible(true);
  24.                             }
  25.                             // 获取对应属性get所得到的值
  26.                             Object value = rm.invoke(source, new Object[0]);
  27.                             if (!Modifier.isPublic(wm.getDeclaringClass().getModifiers())) {
  28.                                 wm.setAccessible(true);
  29.                             }
  30.                             // 调用目标类对应属性的set方法对该属性进行填充
  31.                             wm.invoke((Object) target, new Object[] { value });
  32.                             break;
  33.                         }
  34.                     }
  35.                 }
  36.             }
  37.         } catch (IntrospectionException e) {
  38.             e.printStackTrace();
  39.         } catch (IllegalArgumentException e) {
  40.             e.printStackTrace();
  41.         } catch (IllegalAccessException e) {
  42.             e.printStackTrace();
  43.         } catch (InvocationTargetException e) {
  44.             e.printStackTrace();
  45.         }
  46.     }

修改后支持Map的代码:

  1. /**
  2.      * 实现将源类属性拷贝到目标类中
  3.      * 
  4.      * @param Map map
  5.      * @param Object obj
  6.      */
  7.     public static void copyProperties(Map map, Object obj) throws Exception {
  8.         // 获取目标类的属性信息
  9.         BeanInfo targetbean = Introspector.getBeanInfo(obj.getClass());
  10.         PropertyDescriptor[] propertyDescriptors = targetbean.getPropertyDescriptors();
  11.         // 对每个目标类的属性查找set方法,并进行处理
  12.         for (int i = 0; i < propertyDescriptors.length; i++) {
  13.             PropertyDescriptor pro = propertyDescriptors[i];
  14.             Method wm = pro.getWriteMethod();
  15.             if (wm != null) {// 当目标类的属性具有set方法时,查找源类中是否有相同属性的get方法
  16.                 Iterator ite = map.keySet().iterator();
  17.                 while (ite.hasNext()) {
  18.                     String key = (String) ite.next();
  19.                     // 判断匹配
  20.                     if (key.equals(pro.getName())) {
  21.                         if (!Modifier.isPublic(wm.getDeclaringClass().getModifiers())) {
  22.                             wm.setAccessible(true);
  23.                         }
  24.                         Object value = ((String[]) map.get(key))[0];
  25.                         // 调用目标类对应属性的set方法对该属性进行填充
  26.                         wm.invoke((Object) obj, new Object[] { value });
  27.                         break;
  28.                     }
  29.                 }
  30.             }
  31.         }
  32.     }

上次写的那个方法只适用于String类型。今天扩展了一下,写成了一个类,支持int/Integer、Date和自定义对象。

  1. import java.beans.BeanInfo;
  2. import java.beans.Introspector;
  3. import java.beans.PropertyDescriptor;
  4. import java.lang.reflect.InvocationTargetException;
  5. import java.lang.reflect.Method;
  6. import java.lang.reflect.Modifier;
  7. import java.text.ParseException;
  8. import java.text.SimpleDateFormat;
  9. import java.util.Date;
  10. import java.util.Iterator;
  11. import java.util.Map;
  12. public class BeanUtils {
  13.     public static String DATE_FORMAT = "yyyy-MM-dd";
  14.     public static String[] TYPE_SIMPLE = {"java.lang.Integer","int","java.util.Date"};
  15.     public static String TYPE_INTEGER = "java.lang.Integer,int";
  16.     public static String TYPE_DATE = "java.util.Date";
  17.     
  18.     /**
  19.      * 得到空格之后的字符
  20.      * 
  21.      * @param String type
  22.      * @param String str
  23.      * @return Date
  24.      * @throws ParseException
  25.      */
  26.     public static String splitSpace(String str) throws ParseException{
  27.         if(str.contains(" ")){
  28.             return str.split(" ")[1];
  29.         } else {
  30.             return str;
  31.         }
  32.     }
  33.     
  34.     /**
  35.      * 判断是否是简单数据类型
  36.      * 
  37.      * @param String type
  38.      */
  39.     public static boolean isSimpleType(String type) {
  40.         for (int i = 0; i < TYPE_SIMPLE.length; i++) {
  41.             if (type.equals(TYPE_SIMPLE[i])) {
  42.                 return true;
  43.             }
  44.         }
  45.         return false;
  46.     }
  47.     /**
  48.      * 把String类型转换为Integer
  49.      * 
  50.      * @param String str
  51.      * @return Integer
  52.      */
  53.     public static Integer parseInteger(String str){
  54.         if(str == null || str.equals("")){
  55.             return 0;
  56.         } else {
  57.             return Integer.parseInt(str);
  58.         }
  59.     }
  60.     
  61.     /**
  62.      * 把String类型转换为Date
  63.      * 
  64.      * @param String str
  65.      * @return Date
  66.      * @throws ParseException
  67.      */
  68.     public static Date parseDate(String str) throws ParseException{
  69.         if(str == null || str.equals("")){
  70.             return null;
  71.         } else {
  72.             SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
  73.             Date date = sdf.parse(str);
  74.             return date;
  75.         }
  76.     }
  77.     
  78.     /**
  79.      * 转换对象(用户定义的对象)。设置对象的Id。
  80.      * 
  81.      * @param Class clazz
  82.      * @param  String str
  83.      * @return Object
  84.      * @throws IllegalAccessException 
  85.      * @throws InstantiationException 
  86.      * @throws NoSuchMethodException 
  87.      * @throws SecurityException 
  88.      * @throws InvocationTargetException 
  89.      * @throws IllegalArgumentException 
  90.      * @throws ParseException
  91.      */
  92.     public static Object parseObject(Class clazz, String str) throws InstantiationException, IllegalAccessException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
  93.         Object obj;
  94.         if(str == null || str.equals("")){
  95.             obj = null;
  96.         } else {
  97.             obj = clazz.newInstance();
  98.             Method m = clazz.getMethod("setId",str.getClass());
  99.             m.invoke(obj,str);
  100.         }
  101.         return obj;
  102.     }
  103.     
  104.     /**
  105.      * 根据类型进行转换
  106.      * 
  107.      * @param Class clazz
  108.      * @param String str
  109.      * @return Object
  110.      * @throws ParseException
  111.      * @throws IllegalAccessException 
  112.      * @throws InstantiationException 
  113.      * @throws InvocationTargetException 
  114.      * @throws NoSuchMethodException 
  115.      * @throws IllegalArgumentException 
  116.      * @throws SecurityException 
  117.      */
  118.     public static Object parseByType(Class clazz, String str) throws ParseException, InstantiationException, IllegalAccessException, SecurityException, IllegalArgumentException, NoSuchMethodException, InvocationTargetException{
  119.         Object r = "";
  120.         String clazzName = splitSpace(clazz.getName());
  121.         if (isSimpleType(clazzName)){
  122.             if (TYPE_INTEGER.contains(clazzName)) {
  123.                 r = parseInteger(str);
  124.             } else if (TYPE_DATE.contains(clazzName)) {
  125.                 r = parseDate(str);
  126.             }
  127.         } else {
  128.             r = parseObject(clazz, str);
  129.         }
  130.         return r;
  131.     }
  132.     
  133.     /** 实现将源类(Map类型)属性拷贝到目标类中
  134.        * @param Map map 
  135.        * @param Object obj
  136.        */
  137.     public static void copyProperties(Map map, Object obj) throws Exception {
  138.         // 获取目标类的属性信息
  139.         BeanInfo targetbean = Introspector.getBeanInfo(obj.getClass());
  140.         PropertyDescriptor[] propertyDescriptors = targetbean.getPropertyDescriptors();
  141.         // 对每个目标类的属性查找set方法,并进行处理
  142.         for (int i = 0; i < propertyDescriptors.length; i++) {
  143.             PropertyDescriptor pro = propertyDescriptors[i];
  144.             Method wm = pro.getWriteMethod();
  145.             if (wm != null) {
  146.                 Iterator ite = map.keySet().iterator();
  147.                 while (ite.hasNext()) {
  148.                     String key = (String) ite.next();
  149.                     // 判断匹配
  150.                     if (key.toLowerCase().equals(pro.getName().toLowerCase())) {
  151.                         if (!Modifier.isPublic(wm.getDeclaringClass().getModifiers())) {
  152.                             wm.setAccessible(true);
  153.                         }
  154.                         Object value = ((String[]) map.get(key))[0];
  155.                         String pt = splitSpace(pro.getPropertyType().getName());
  156.                         //判断类型是否匹配,不匹配则作强制转换
  157.                         if (!(pt.equals(value.getClass().getName()))) {
  158.                             value = parseByType(pro.getPropertyType(),value.toString());
  159.                         }
  160.                         // 调用目标类对应属性的set方法对该属性进行填充
  161.                         wm.invoke((Object) obj, new Object[] {value});
  162.                         break;
  163.                     }
  164.                 }
  165.             }
  166.         }
  167.     }
  168. }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值