最近,项目组要用到一个功能,就是用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
6. try
7. // 获取目标类的属性信息 
8.             BeanInfo targetbean = Introspector.getBeanInfo(target.getClass());
9.             PropertyDescriptor[] propertyDescriptors = targetbean
10.                     .getPropertyDescriptors();
11. // 对每个目标类的属性查找set方法,并进行处理 
12. for (int
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
19. if (sourcepds[j].getName().equals(pro.getName())) { // 匹配 
20.                             Method rm = sourcepds[j].getReadMethod();
21. // 如果方法不可访问(get方法是私有的或不可达),则抛出SecurityException 
22. if
23. true);
24.                             }
25. // 获取对应属性get所得到的值 
26. new
27. if
28. true);
29.                             }
30. // 调用目标类对应属性的set方法对该属性进行填充 
31. new
32. break;
33.                         }
34.                     }
35.                 }
36.             }
37. catch
38.             e.printStackTrace();
39. catch
40.             e.printStackTrace();
41. catch
42.             e.printStackTrace();
43. catch
44.             e.printStackTrace();
45.         }
46.     }


修改后支持Map的代码:

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


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

1. 
2. import
3. import
4. import
5. import
6. import
7. import
8. import
9. import
10. import
11. import
12. import
13. 
14. public class
15. public static String DATE_FORMAT = "yyyy-MM-dd";
16. public static String[] TYPE_SIMPLE = {"java.lang.Integer","int","java.util.Date"};
17. public static String TYPE_INTEGER = "java.lang.Integer,int";
18. public static String TYPE_DATE = "java.util.Date";
19.     
20. /**
21.      * 得到空格之后的字符
22.      * 
23.      * @param String type
24.      * @param String str
25.      * @return Date
26.      * @throws ParseException
27.      */
28. public static String splitSpace(String str) throws
29. if(str.contains(" ")){

30. return str.split(" ")[1];
31. else
32. return
33.         }
34.     }
35.     
36. /**
37.      * 判断是否是简单数据类型
38.      * 
39.      * @param String type
40.      */
41. public static boolean
42. for (int i = 0; i < TYPE_SIMPLE.length; i++) {

43. if
44. return true;
45.             }
46.         }
47. return false;
48.     }
49. /**
50.      * 把String类型转换为Integer
51.      * 
52.      * @param String str
53.      * @return Integer
54.      */
55. public static
56. if(str == null || str.equals("")){

57. return 0;
58. else
59. return
60.         }
61.     }
62.     
63. /**
64.      * 把String类型转换为Date
65.      * 
66.      * @param String str
67.      * @return Date
68.      * @throws ParseException
69.      */
70. public static Date parseDate(String str) throws
71. if(str == null || str.equals("")){

72. return null;
73. else
74. new
75.             Date date = sdf.parse(str);
76. return
77.         }
78.     }
79.     
80. /**
81.      * 转换对象(用户定义的对象)。设置对象的Id。
82.      * 
83.      * @param Class clazz
84.      * @param  String str
85.      * @return Object
86.      * @throws IllegalAccessException 
87.      * @throws InstantiationException 
88.      * @throws NoSuchMethodException 
89.      * @throws SecurityException 
90.      * @throws InvocationTargetException 
91.      * @throws IllegalArgumentException 
92.      * @throws ParseException
93.      */
94. public static Object parseObject(Class clazz, String str) throws
95.         Object obj;
96. if(str == null || str.equals("")){

97. null;
98. else
99.             obj = clazz.newInstance();
100. "setId",str.getClass());
101.             m.invoke(obj,str);
102.         }
103. return
104.     }
105.     
106. /**
107.      * 根据类型进行转换
108.      * 
109.      * @param Class clazz
110.      * @param String str
111.      * @return Object
112.      * @throws ParseException
113.      * @throws IllegalAccessException 
114.      * @throws InstantiationException 
115.      * @throws InvocationTargetException 
116.      * @throws NoSuchMethodException 
117.      * @throws IllegalArgumentException 
118.      * @throws SecurityException 
119.      */
120. public static Object parseByType(Class clazz, String str) throws
121. "";
122.         String clazzName = splitSpace(clazz.getName());
123. if
124. if
125.                 r = parseInteger(str);
126. else if
127.                 r = parseDate(str);
128.             }
129. else
130.             r = parseObject(clazz, str);
131.         }
132. return
133.     }
134.     
135. /** 实现将源类(Map类型)属性拷贝到目标类中
136.        * @param Map map 
137.        * @param Object obj
138.        */
139. public static void copyProperties(Map map, Object obj) throws
140. // 获取目标类的属性信息 
141.         BeanInfo targetbean = Introspector.getBeanInfo(obj.getClass());
142.         PropertyDescriptor[] propertyDescriptors = targetbean.getPropertyDescriptors();
143. // 对每个目标类的属性查找set方法,并进行处理 
144. for (int i = 0; i < propertyDescriptors.length; i++) {

145.             PropertyDescriptor pro = propertyDescriptors[i];
146.             Method wm = pro.getWriteMethod();
147. if (wm != null) {

148.                 Iterator ite = map.keySet().iterator();
149. while
150.                     String key = (String) ite.next();
151. // 判断匹配 
152. if
153. if
154. true);
155.                         }
156. 0];
157.                         String pt = splitSpace(pro.getPropertyType().getName());
158. //判断类型是否匹配,不匹配则作强制转换 
159. if
160.                             value = parseByType(pro.getPropertyType(),value.toString());
161.                         }
162. // 调用目标类对应属性的set方法对该属性进行填充 
163. new
164. break;
165.                     }
166.                 }
167.             }
168.         }
169.     }
170. }