Java中Map转换成POJO的方法

在项目中,有这样一个需求:我们需要把一个Map<String,Object>转换成POJO(POJO中的属性类型不一样)

实现

一个简单实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 通过泛型和反射自动Mapper数据
*/
public class MapperUtil<T> {

public <T> T mapperObj(Map<String,Object> map,Class<T> t) throws Exception{
if (map == null || map.size() == 0) {
return t.newInstance();
}
Object tobj = t.newInstance();
for (Object key : map.keySet()) {
Field field = t.getDeclaredField((String) key);
field.setAccessible(true);
field.set(tobj, map.get(key));
}
return (T) tobj;
}
}

增加按照类型进行转换,关键步骤:获取属性的set方法,然后我们要判断set的参数类型是什么,包括了String、Int、Double等基本类型,还可能是数组等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* 通过泛型和反射自动Mapper数据
*/
public class MapperUtil<T> {

public <T> T mapperObj(Map<String,Object> map,Class<T> t) throws Exception{
if (map == null || map.size() == 0) {
return t.newInstance();
}
Object tobj = t.newInstance();
for (Map.Entry<String,Object> entry : map.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
// 根据属性类型进行转换
PropertyDescriptor pd = new PropertyDescriptor(key, t);
// 获得写方法,然后获取类型
Method wM = pd.getWriteMethod();
Class<?> parameterType = wM.getParameterTypes()[0];
if (parameterType == int.class || parameterType == Integer.class) {
String str = String.valueOf(value);
if (StringUtils.isNotBlank(str)) {
wM.invoke(tobj, new BigDecimal(String.valueOf(value)).intValue());
}
} else if (parameterType == double.class || parameterType == Double.class) {
String str = String.valueOf(value);
if (StringUtils.isNotBlank(str)) {
wM.invoke(tobj, new BigDecimal(String.valueOf(value)).doubleValue());
}
} else {
wM.invoke(tobj, String.valueOf(value));
}
}
return (T) tobj;
}
}

不过,使用PropertyDescriptor去获取属性,一定要保证POJO对象里设置get和set书写规范!

比如属性为:

1
private String mBuyPrice;

使用Idea或者Eclipse自动生成getter和setter方法时,会生成如下:

1
2
3
4
5
6
7
8
9
10
11
public class Price {
private String mBuyPrice;

public String getmBuyPrice() {
return mBuyPrice;
}

public void setmBuyPrice(String mBuyPrice) {
this.mBuyPrice = mBuyPrice;
}
}

获取属性时会报错:java.beans.IntrospectionException: Method not found: isMBuyPrice。因为JavaBean属性名要求:前两个字母要么都大写,要么都小写

相关知识-反射

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

获取某个对象的属性

1
2
3
4
5
6
7
8
9
public Object getProperty(Object owner, String fieldName) throws Exception {     
// 得到该对象的Class
Class ownerClass = owner.getClass();
// 通过Class得到类声明的属性
Field field = ownerClass.getField(fieldName);
// 通过对象得到该属性的实例,如果这个属性是非公有的,这里会报IllegalAccessException
Object property = field.get(owner);
return property;
}

获取某个类的静态属性

1
2
3
4
5
6
7
8
9
public Object getStaticProperty(String className, String fieldName) throws Exception {     
// 通过这种方式获得类型的要注意,参数是包名+类名
Class ownerClass = Class.forName(className);
// 通过Class得到类声明的属性
Field field = ownerClass.getField(fieldName);
// 这里和上面有些不同,因为该属性是静态的,所以直接从类的Class里取
Object property = field.get(ownerClass);
return property;
}

执行某对象的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
public Object invokeMethod(Object owner, String methodName, Object[] args) throws Exception {     
// 得到该对象的Class
Class ownerClass = owner.getClass();
// 配置参数的Class数组,作为寻找Method的条件
Class[] argsClass = new Class[args.length];
for (int i = 0, j = args.length; i < j; i++) {
argsClass[i] = args[i].getClass();
}
// 通过methodName和参数的argsClass(方法中的参数类型集合)数组得到要执行的Method
Method method = ownerClass.getMethod(methodName,argsClass);
// 执行owner对象中带有参数args的method方法
return method.invoke(owner, args);
}

执行某个类的静态方法

1
2
3
4
5
6
7
8
9
10
11
12
13
public Object invokeStaticMethod(String className, String methodName, Object[] args) throws Exception {  
// 得到该对象的Class
Class ownerClass = Class.forName(className);
// 配置参数的Class数组,作为寻找Method的条件
Class[] argsClass = new Class[args.length];
for (int i = 0, j = args.length; i < j; i++) {
argsClass[i] = args[i].getClass();
}
// 通过methodName和参数的argsClass(方法中的参数类型集合)数组得到要执行的Method
Method method = ownerClass.getMethod(methodName,argsClass);
// invoke的一个参数是null,因为这是静态方法,不需要借助实例运行
return method.invoke(null, args);
}

新建实例

1
2
3
4
5
6
7
8
9
10
11
12
13
public Object newInstance(String className, Object[] args) throws Exception {     
// 得到要构造的实例的Class
Class newoneClass = Class.forName(className);
// 得到参数的Class数组
Class[] argsClass = new Class[args.length];
for (int i = 0, j = args.length; i < j; i++) {
argsClass[i] = args[i].getClass();
}
// 得到构造子
Constructor cons = newoneClass.getConstructor(argsClass);
// 新建实例
return cons.newInstance(args);
}

参考


----------- 本文结束啦感谢您阅读 -----------

赞赏一杯咖啡

欢迎关注我的其它发布渠道