最近,项目组要用到一个功能,就是用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. }