1 package com.xnky.pams.common.utils;
2
3 import org.slf4j.Logger;
4 import org.slf4j.LoggerFactory;
5
6 import java.lang.reflect.Field;
7 import java.lang.reflect.Method;
8 import java.lang.reflect.ParameterizedType;
9 import java.lang.reflect.Type;
10 import java.math.BigDecimal;
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.Date;
14 import java.util.HashMap;
15 import java.util.HashSet;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Set;
19 import java.util.concurrent.ConcurrentHashMap;
20
21
22 /**
23 * 把对象A中属性的值传给对象B相同类型的属性。
24 *
25 * @author Feng Yongkang, 2019/8/6
26 * @version v1.0
27 */
28 public class PojoConvertUtil {
29 private static Logger logger = LoggerFactory.getLogger(PojoConvertUtil.class);
30 /**
31 * 变量缓存.
32 */
33 private static final Map<String, Map<String, Field>> CACHE_FIELDS = new ConcurrentHashMap<>();
34 private static final Set<Class> BASIC_CLASS = new HashSet<>();
35
36 static {
37 BASIC_CLASS.add(Integer.class);
38 BASIC_CLASS.add(Character.class);
39 BASIC_CLASS.add(Byte.class);
40 BASIC_CLASS.add(Float.class);
41 BASIC_CLASS.add(Double.class);
42 BASIC_CLASS.add(Boolean.class);
43 BASIC_CLASS.add(Long.class);
44 BASIC_CLASS.add(Short.class);
45 BASIC_CLASS.add(String.class);
46 BASIC_CLASS.add(BigDecimal.class);
47 }
48
49 private PojoConvertUtil() {
50 }
51
52 /**
53 * 将具有相同属性的类型进行转换.
54 *
55 * @param orig 原始对象
56 * @param targetClass 目标对象
57 * @param <T> 泛型
58 * @return 泛型
59 */
60 public static <T> T convertPojo(Object orig, Class<T> targetClass) {
61 try {
62 T target = targetClass.newInstance();
63 /** 获取源对象的所有变量 */
64 Field[] fields = orig.getClass().getDeclaredFields();
65 for (Field field : fields) {
66 if (isStatic(field)) {
67 continue;
68 }
69 /** 获取目标对象与原对象相同的字段 */
70 Field targetField = getTargetField(targetClass, field.getName());
71 if (targetField == null) {
72 continue;
73 }
74 /*获取原对象中字段的值*/
75 Object value = getFiledValue(field, orig);
76 if (value == null) {
77 continue;
78 }
79 Class type1 = field.getType();
80 Class type2 = targetField.getType();
81 //两个类型是否相同
82 boolean sameType = type1.equals(type2);
83 if (isBasicType(type1)) {
84 if (sameType) {
85 setFieldValue(targetField, target, value);
86 }
87 } else if (value instanceof Map && Map.class.isAssignableFrom(type2)) {//对map
88 setMap((Map) value, field, targetField, target);
89 } else if (value instanceof Set && Set.class.isAssignableFrom(type2)) {//对set
90 setCollection((Collection) value, field, targetField, target);
91 } else if (value instanceof List && List.class.isAssignableFrom(type2)) {//对list
92 setCollection((Collection) value, field, targetField, target);
93 } else if (value instanceof Enum && Enum.class.isAssignableFrom(type2)) {//对enum
94 setEnum((Enum) value, field, targetField, target);
95 } else if (value instanceof java.util.Date
96 && java.util.Date.class.isAssignableFrom(type2)) {//对日期类型,不处理如joda包之类的扩展时间,不处理calendar
97 setDate((Date) value, targetField, type2, target, sameType);
98 }
99 }
100 return target;
101 } catch (Throwable t) {
102 logger.error("转换失败:" + t.getMessage());
103 throw new RuntimeException(t.getMessage());
104 }
105 }
106
107 /**
108 * 获取字段值.
109 *
110 * @param field
111 * @param obj
112 * @return
113 */
114 private static Object getFiledValue(Field field, Object obj) throws IllegalAccessException {
115 //获取原有的访问权限
116 boolean access = field.isAccessible();
117 try {
118 //设置可访问的权限
119 field.setAccessible(true);
120 return field.get(obj);
121 } finally {
122 //恢复访问权限
123 field.setAccessible(access);
124 }
125 }
126
127 /**
128 * 设置属性值.
129 * 之所以这里用对象 对象的方法 和要传入的值 ,前两者都是一个对象里面的内容,对于这个方法来说,对象类型是不确定的。
130 *
131 * @param field
132 * @param obj
133 * @param value
134 * @throws IllegalAccessException
135 */
136 private static void setFieldValue(Field field, Object obj, Object value) throws IllegalAccessException {
137 //获取原有的访问权限
138 boolean access = field.isAccessible();
139 try {
140 //设置可访问的权限
141 field.setAccessible(true);
142 field.set(obj, value);
143 } finally {
144 //恢复访问权限
145 field.setAccessible(access);
146 }
147 }
148
149 /**
150 * 转换list.
151 *
152 * @param orig 原始list
153 * @param targetClass 目标list
154 * @param <T> 泛型
155 * @return 泛型
156 */
157 public static <T> List<T> convertPojos(List orig, Class<T> targetClass) {
158 List<T> list = new ArrayList<>(orig.size());
159 for (Object object : orig) {
160 list.add(convertPojo(object, targetClass));
161 }
162 return list;
163 }
164
165 /**
166 * 设置Map.
167 *
168 * @param value 要转换的数据
169 * @param origField 原对象的字段
170 * @param targetField 目标对象的字段
171 * @param targetObject 目标对象
172 * @param <T> 泛型
173 */
174 private static <T> void setMap(Map value, Field origField, Field targetField
175 , T targetObject) throws IllegalAccessException, InstantiationException {
176 Type origType = origField.getGenericType();
177 Type targetType = targetField.getGenericType();
178 if (origType instanceof ParameterizedType && targetType instanceof ParameterizedType) {//泛型类型
179 ParameterizedType origParameterizedType = (ParameterizedType) origType;
180 Type[] origTypes = origParameterizedType.getActualTypeArguments();
181 ParameterizedType targetParameterizedType = (ParameterizedType) targetType;
182 Type[] targetTypes = targetParameterizedType.getActualTypeArguments();
183 if (origTypes != null && origTypes.length == 2 && targetTypes != null && targetTypes.length == 2) {
184 Class clazz = (Class) origTypes[1];
185 if (!isBasicType(clazz) && !clazz.equals(targetTypes[1])) {//如果不是基本类型并且泛型不一致,则需要继续转换
186 Set<Map.Entry> entries = value.entrySet();
187 Map targetMap = value.getClass().newInstance();
188 for (Map.Entry entry : entries) {
189 targetMap.put(entry.getKey(), convertPojo(entry.getValue(), (Class) targetTypes[1]));
190 }
191 setFieldValue(targetField, targetObject, targetMap);
192 return;
193 }
194 }
195 }
196 setFieldValue(targetField, targetObject, value);
197 }
198
199 /**
200 * 设置集合.
201 *
202 * @param value
203 * @param origField
204 * @param targetField
205 * @param targetObject
206 * @param <T>
207 * @throws IllegalAccessException
208 * @throws InstantiationException
209 */
210 private static <T> void setCollection(Collection value, Field origField, Field targetField
211 , T targetObject) throws IllegalAccessException, InstantiationException {
212 Type origType = origField.getGenericType();
213 Type targetType = targetField.getGenericType();
214 if (origType instanceof ParameterizedType && targetType instanceof ParameterizedType) {//泛型类型
215 ParameterizedType origParameterizedType = (ParameterizedType) origType;
216 Type[] origTypes = origParameterizedType.getActualTypeArguments();
217 ParameterizedType targetParameterizedType = (ParameterizedType) targetType;
218 Type[] targetTypes = targetParameterizedType.getActualTypeArguments();
219 //正常泛型,查看第二个泛型是否不为基本类型
220 if (origTypes != null && origTypes.length == 1 && targetTypes != null && targetTypes.length == 1) {
221 Class clazz = (Class) origTypes[0];
222 if (!isBasicType(clazz) && !clazz.equals(targetTypes[0])) {//如果不是基本类型并且泛型不一致,则需要继续转换
223 Collection collection = value.getClass().newInstance();
224 for (Object obj : value) {
225 collection.add(convertPojo(obj, (Class) targetTypes[0]));
226 }
227 setFieldValue(targetField, targetObject, collection);
228 return;
229 }
230 }
231 }
232 setFieldValue(targetField, targetObject, value);
233 }
234
235 /**
236 * 设置枚举类型.
237 *
238 * @param value
239 * @param origField
240 * @param targetField
241 * @param targetObject
242 * @param <T>
243 */
244 private static <T> void setEnum(Enum value, Field origField, Field targetField, T targetObject) throws Exception {
245 if (origField.equals(targetField)) {
246 setFieldValue(targetField, targetObject, value);
247 } else {
248 //枚举类型都具有一个static修饰的valueOf方法
249 Method method = targetField.getType().getMethod("valueOf", String.class);
250 setFieldValue(targetField, targetObject, method.invoke(null, value.toString()));
251 }
252 }
253
254 /**
255 * 设置日期类型.
256 *
257 * @param value
258 * @param targetField
259 * @param targetFieldType
260 * @param targetObject
261 * @param <T>
262 */
263 private static <T> void setDate(Date value, Field targetField, Class targetFieldType
264 , T targetObject, boolean sameType) throws IllegalAccessException {
265 Date date = null;
266 if (sameType) {
267 date = value;
268 } else if (targetFieldType.equals(java.sql.Date.class)) {
269 date = new java.sql.Date(value.getTime());
270 } else if (targetFieldType.equals(java.util.Date.class)) {
271 date = new Date(value.getTime());
272 } else if (targetFieldType.equals(java.sql.Timestamp.class)) {
273 date = new java.sql.Timestamp(value.getTime());
274 }
275 setFieldValue(targetField, targetObject, date);
276 }
277
278 /**
279 * 获取适配方法.
280 * 把目标类全部字段放到map中,并把这把map放入CACHE_FIELDS。
281 *
282 * @param clazz 类型
283 * @param fieldName 字段名
284 * @return 目标类型中与原对象属性名一致的字段
285 */
286 public static Field getTargetField(Class clazz, String fieldName) {
287 String classKey = clazz.getName();
288 //如果下次再来查找同一个类的所有字段,可以在CACHE_FIELDS找之前存过的包含该类型多有字段的map
289 Map<String, Field> fieldMap = CACHE_FIELDS.get(classKey);
290 if (fieldMap == null) {
291 fieldMap = new HashMap<>();
292 Field[] fields = clazz.getDeclaredFields();
293 for (Field field : fields) {
294 if (isStatic(field)) {
295 continue;
296 }
297 fieldMap.put(field.getName(), field);
298 }
299 CACHE_FIELDS.put(classKey, fieldMap);
300 }
301 return fieldMap.get(fieldName);
302 }
303
304 /**
305 * 判断是否为基础类型.
306 *
307 * @param clazz 类型
308 * @return true是 false 否
309 */
310 public static boolean isBasicType(Class clazz) {
311 return clazz.isPrimitive() || BASIC_CLASS.contains(clazz);
312 }
313
314 /**
315 * 判断变量是否有静态修饰符static.
316 *
317 * @param field 要判断的字段
318 * @return 是否有静态修饰
319 */
320 public static boolean isStatic(Field field) {
321 return (8 & field.getModifiers()) == 8;
322 }
323 }
/*
* Copyright (c) Travelsky Corp.
* All Rights Reserved.
*/
package com.xnky.pams.common.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* PojoConvertUtil.
* 把对象A中属性的值传给对象B相同类型的属性。
*
* @author Feng Yongkang, 2019/8/6
* @version v1.0
*/
public class PojoConvertUtil {
private static Logger logger = LoggerFactory.getLogger(PojoConvertUtil.class);
/**
* 变量缓存.
*/
private static final Map<String, Map<String, Field>> CACHE_FIELDS = new ConcurrentHashMap<>();
private static final Set<Class> BASIC_CLASS = new HashSet<>();
static {
BASIC_CLASS.add(Integer.class);
BASIC_CLASS.add(Character.class);
BASIC_CLASS.add(Byte.class);
BASIC_CLASS.add(Float.class);
BASIC_CLASS.add(Double.class);
BASIC_CLASS.add(Boolean.class);
BASIC_CLASS.add(Long.class);
BASIC_CLASS.add(Short.class);
BASIC_CLASS.add(String.class);
BASIC_CLASS.add(BigDecimal.class);
}
private PojoConvertUtil() {
}
/**
* 将具有相同属性的类型进行转换.
*
* @param orig 原始对象
* @param targetClass 目标对象
* @param <T> 泛型
* @return 泛型
*/
public static <T> T convertPojo(Object orig, Class<T> targetClass) {
try {
T target = targetClass.newInstance();
/** 获取源对象的所有变量 */
Field[] fields = orig.getClass().getDeclaredFields();
for (Field field : fields) {
if (isStatic(field)) {
continue;
}
/** 获取目标对象与原对象相同的字段 */
Field targetField = getTargetField(targetClass, field.getName());
if (targetField == null) {
continue;
}
/*获取原对象中字段的值*/
Object value = getFiledValue(field, orig);
if (value == null) {
continue;
}
Class type1 = field.getType();
Class type2 = targetField.getType();
//两个类型是否相同
boolean sameType = type1.equals(type2);
if (isBasicType(type1)) {
if (sameType) {
setFieldValue(targetField, target, value);
}
} else if (value instanceof Map && Map.class.isAssignableFrom(type2)) {//对map
setMap((Map) value, field, targetField, target);
} else if (value instanceof Set && Set.class.isAssignableFrom(type2)) {//对set
setCollection((Collection) value, field, targetField, target);
} else if (value instanceof List && List.class.isAssignableFrom(type2)) {//对list
setCollection((Collection) value, field, targetField, target);
} else if (value instanceof Enum && Enum.class.isAssignableFrom(type2)) {//对enum
setEnum((Enum) value, field, targetField, target);
} else if (value instanceof java.util.Date
&& java.util.Date.class.isAssignableFrom(type2)) {//对日期类型,不处理如joda包之类的扩展时间,不处理calendar
setDate((Date) value, targetField, type2, target, sameType);
}
}
return target;
} catch (Throwable t) {
logger.error("转换失败:" + t.getMessage());
throw new RuntimeException(t.getMessage());
}
}
/**
* 获取字段值.
*
* @param field
* @param obj
* @return
*/
private static Object getFiledValue(Field field, Object obj) throws IllegalAccessException {
//获取原有的访问权限
boolean access = field.isAccessible();
try {
//设置可访问的权限
field.setAccessible(true);
return field.get(obj);
} finally {
//恢复访问权限
field.setAccessible(access);
}
}
/**
* 设置属性值.
* 之所以这里用对象 对象的方法 和要传入的值 ,前两者都是一个对象里面的内容,对于这个方法来说,对象类型是不确定的。
*
* @param field
* @param obj
* @param value
* @throws IllegalAccessException
*/
private static void setFieldValue(Field field, Object obj, Object value) throws IllegalAccessException {
//获取原有的访问权限
boolean access = field.isAccessible();
try {
//设置可访问的权限
field.setAccessible(true);
field.set(obj, value);
} finally {
//恢复访问权限
field.setAccessible(access);
}
}
/**
* 转换list.
*
* @param orig 原始list
* @param targetClass 目标list
* @param <T> 泛型
* @return 泛型
*/
public static <T> List<T> convertPojos(List orig, Class<T> targetClass) {
List<T> list = new ArrayList<>(orig.size());
for (Object object : orig) {
list.add(convertPojo(object, targetClass));
}
return list;
}
/**
* 设置Map.
*
* @param value 要转换的数据
* @param origField 原对象的字段
* @param targetField 目标对象的字段
* @param targetObject 目标对象
* @param <T> 泛型
*/
private static <T> void setMap(Map value, Field origField, Field targetField
, T targetObject) throws IllegalAccessException, InstantiationException {
Type origType = origField.getGenericType();
Type targetType = targetField.getGenericType();
if (origType instanceof ParameterizedType && targetType instanceof ParameterizedType) {//泛型类型
ParameterizedType origParameterizedType = (ParameterizedType) origType;
Type[] origTypes = origParameterizedType.getActualTypeArguments();
ParameterizedType targetParameterizedType = (ParameterizedType) targetType;
Type[] targetTypes = targetParameterizedType.getActualTypeArguments();
if (origTypes != null && origTypes.length == 2 && targetTypes != null && targetTypes.length == 2) {
Class clazz = (Class) origTypes[1];
if (!isBasicType(clazz) && !clazz.equals(targetTypes[1])) {//如果不是基本类型并且泛型不一致,则需要继续转换
Set<Map.Entry> entries = value.entrySet();
Map targetMap = value.getClass().newInstance();
for (Map.Entry entry : entries) {
targetMap.put(entry.getKey(), convertPojo(entry.getValue(), (Class) targetTypes[1]));
}
setFieldValue(targetField, targetObject, targetMap);
return;
}
}
}
setFieldValue(targetField, targetObject, value);
}
/**
* 设置集合.
*
* @param value
* @param origField
* @param targetField
* @param targetObject
* @param <T>
* @throws IllegalAccessException
* @throws InstantiationException
*/
private static <T> void setCollection(Collection value, Field origField, Field targetField
, T targetObject) throws IllegalAccessException, InstantiationException {
Type origType = origField.getGenericType();
Type targetType = targetField.getGenericType();
if (origType instanceof ParameterizedType && targetType instanceof ParameterizedType) {//泛型类型
ParameterizedType origParameterizedType = (ParameterizedType) origType;
Type[] origTypes = origParameterizedType.getActualTypeArguments();
ParameterizedType targetParameterizedType = (ParameterizedType) targetType;
Type[] targetTypes = targetParameterizedType.getActualTypeArguments();
//正常泛型,查看第二个泛型是否不为基本类型
if (origTypes != null && origTypes.length == 1 && targetTypes != null && targetTypes.length == 1) {
Class clazz = (Class) origTypes[0];
if (!isBasicType(clazz) && !clazz.equals(targetTypes[0])) {//如果不是基本类型并且泛型不一致,则需要继续转换
Collection collection = value.getClass().newInstance();
for (Object obj : value) {
collection.add(convertPojo(obj, (Class) targetTypes[0]));
}
setFieldValue(targetField, targetObject, collection);
return;
}
}
}
setFieldValue(targetField, targetObject, value);
}
/**
* 设置枚举类型.
*
* @param value
* @param origField
* @param targetField
* @param targetObject
* @param <T>
*/
private static <T> void setEnum(Enum value, Field origField, Field targetField, T targetObject) throws Exception {
if (origField.equals(targetField)) {
setFieldValue(targetField, targetObject, value);
} else {
//枚举类型都具有一个static修饰的valueOf方法
Method method = targetField.getType().getMethod("valueOf", String.class);
setFieldValue(targetField, targetObject, method.invoke(null, value.toString()));
}
}
/**
* 设置日期类型.
*
* @param value
* @param targetField
* @param targetFieldType
* @param targetObject
* @param <T>
*/
private static <T> void setDate(Date value, Field targetField, Class targetFieldType
, T targetObject, boolean sameType) throws IllegalAccessException {
Date date = null;
if (sameType) {
date = value;
} else if (targetFieldType.equals(java.sql.Date.class)) {
date = new java.sql.Date(value.getTime());
} else if (targetFieldType.equals(java.util.Date.class)) {
date = new Date(value.getTime());
} else if (targetFieldType.equals(java.sql.Timestamp.class)) {
date = new java.sql.Timestamp(value.getTime());
}
setFieldValue(targetField, targetObject, date);
}
/**
* 获取适配方法.
* 把目标类全部字段放到map中,并把这把map放入CACHE_FIELDS。
*
* @param clazz 类型
* @param fieldName 字段名
* @return 目标类型中与原对象属性名一致的字段
*/
public static Field getTargetField(Class clazz, String fieldName) {
String classKey = clazz.getName();
//如果下次再来查找同一个类的所有字段,可以在CACHE_FIELDS找之前存过的包含该类型多有字段的map
Map<String, Field> fieldMap = CACHE_FIELDS.get(classKey);
if (fieldMap == null) {
fieldMap = new HashMap<>();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (isStatic(field)) {
continue;
}
fieldMap.put(field.getName(), field);
}
CACHE_FIELDS.put(classKey, fieldMap);
}
return fieldMap.get(fieldName);
}
/**
* 判断是否为基础类型.
*
* @param clazz 类型
* @return true是 false 否
*/
public static boolean isBasicType(Class clazz) {
return clazz.isPrimitive() || BASIC_CLASS.contains(clazz);
}
/**
* 判断变量是否有静态修饰符static.
*
* @param field 要判断的字段
* @return 是否有静态修饰
*/
public static boolean isStatic(Field field) {
return (8 & field.getModifiers()) == 8;
}
}