前言
最近在工作的时候,遇到了这样一个问题,我需要
- 将Map集合转换成为一个对应的实体类对象。
- 将一个实体类对象转换成为对应的Map集合。
那么,如果是你,你会怎么做呢?好吧,这里我就不卖关子了,用阿里巴巴的Fastjson就可以了。关于阿里巴巴的Fastjson的具体使用,可以查看我的这篇博客:
当然,在经过上次用反射造轮子之后,我已经不满足用别人写的工具方法了:
至于如何用Fastjson以及手写工具方法完成map和实体类之间的互相转换。接下来,请容我慢慢介绍!
事前准备
首先,我们当然要先准备一个实体类:
/**
* @ClassName Person
* @Description 人类
* @Author 古阙月
* @Date 2020/9/18
* @Version 1.0
*/
@Data // lombok的注解,提供getter、setter以及toString方法
@AllArgsConstructor // lombok的注解,提供全参构造方法
@NoArgsConstructor // lombok的注解,提供无参构造方法
@Accessors(chain = true) // lombok的注解,开启链式编程
public class Person {
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private int age;
}
当然,以上使用了lombok的注解去生成了一些方法,没有下载lombok插件以及导入lombok依赖的话,是无效的,需要自行生成相应的方法。
其次,我们需要一个工具类,用以调用我们手写的方法,里面已经有一个我自己之前手写的将任意实体类对象转换json字符串的方法
/**
* @ClassName MyJson
* @Description 我自己的FastJson
* @Author 古阙月
* @Date 2020/9/18
* @Version 2.0
*/
public class MyJson {
/**
* 将任意实体类对象转换为JSON字符串
* @param object
* @return
*/
public static final String toJsonString(Object object) throws Exception {
// 获取反射对象
Class<?> clazz = object.getClass();
// 获取反射对象的所有属性,包括私有属性
Field[] fields = clazz.getDeclaredFields();
// 创建字符串类,便于拼接出JSON字符串
StringBuffer stringBuffer = new StringBuffer();
String str = "";
stringBuffer.append("{");
// 遍历所有属性
for (Field field : fields) {
// 第一次无须拼接逗号
if (stringBuffer.length() != 1) {
stringBuffer.append(",");
}
// 给私有属性授权,以便能够对于私有属性操作
field.setAccessible(true);
// 获取属性名称
String name = field.getName();
// 获取属性值
Object value = field.get(object);
// 拼接属性名称
stringBuffer.append("\"");
stringBuffer.append(name);
stringBuffer.append("\"");
stringBuffer.append(":");
// 两种判断属性值是否为字符串类型的方式
Boolean flag = field.getType().isInstance(str);
// Boolean flag = field.getType().toString().equals("class java.lang.String");
if (flag && value != null) { // 如果属性的类型为字符串并且不为空,则给属性值加上双引号
stringBuffer.append("\"");
stringBuffer.append(value);
stringBuffer.append("\"");
} else {
stringBuffer.append(value);
}
}
stringBuffer.append("}");
return stringBuffer.toString();
}
}
实体类转Map
Fastjson
用Fastjson将实体类转换成Map非常的简单。在导入了Fastjson的依赖过后,直接将实体类转换成为JSON字符串,再将JSON字符串转换成为Map即可。
/**
* @ClassName EntityToMap
* @Description 用Fasjson将实体类转换成map
* @Author 古阙月
* @Date 2020/9/18
* @Version 1.0
*/
public class EntityToMap {
public static void main(String[] args) {
// 创建一个实体类
Person person = new Person("古阙月", 18);
// 将实体类转换成为json字符串
String jsonString = JSON.toJSONString(person);
// 将json字符串转换成map
HashMap personMap = JSON.parseObject(jsonString, HashMap.class);
// 输出结果到控制台
System.out.println(personMap);
}
}
运行得:
转换成功!
手写工具方法
话不多说,直接上代码:
/**
* 将任意对象转换成所对应的map
* @param object 对象
* @return
*/
public static HashMap entityToMap(Object object) throws Exception {
// 创建一个map对象
HashMap<String, Object> ObjMap = new HashMap<String, Object>();
// 获取反射对象
Class<?> clazz = object.getClass();
// 获取反射对象的所有属性,包括公有属性和私有属性
Field[] fields = clazz.getDeclaredFields();
// 遍历所有属性
for (Field field : fields) {
// 私有属性授权,方便访问
field.setAccessible(true);
// 赋值
ObjMap.put(field.getName(), field.get(object));
}
return ObjMap;
}
测试一下:
/**
* @ClassName EntityToMap
* @Description 用自己手写的方法将实体类转换成map
* @Author 古阙月
* @Date 2020/9/18
* @Version 1.0
*/
public class EntityToMap2 {
public static void main(String[] args) throws Exception {
// 创建一个实体类
Person person = new Person().setAge(0).setName("古阙月");
// 将person对象转换成map
HashMap personMap = MyJson.entityToMap(person);
// 输出结果到控制台
System.out.println(personMap);
}
}
运行得:
一个方法就搞定了,是不是感觉比之前的Fastjson还要方便?
Map转实体类
Fastjson
同样的,用Fastjson将Map转成实体类也很简单。先将Map转成json字符串,再用反射对象将json字符串转换成对应的实体类即可。
/**
1. @ClassName MapToEntity
2. @Description 将map转换成实体类
3. @Author 古阙月
4. @Date 2020/9/18
5. @Version 1.0
*/
public class MapToEntity {
public static void main(String[] args) {
// 创建一个map,map的键名和实体类的属性名称一一对应
HashMap<String, Object> personMap = new HashMap();
personMap.put("name", "小小");
personMap.put("age", 17);
// 将map转换成json字符串
String jsonString = JSON.toJSONString(personMap);
// 将json字符串转换成对应的实体类
Person person = JSON.parseObject(jsonString, Person.class);
// 输出结果
System.out.println(person);
}
}
运行:
转换成功!!!
手写工具方法
之前将实体类转换成Map的手写工具类写法毋庸置疑,遍历得到实体类的属性名称以及属性值然后再一个个往Map中装值便可。但是如果将Map转换成实体类,其实我们会有两个选择:
- 遍历实体类所对应反射对象的所有属性对象,通过属性对象的属性名称来获取Map中的值,再赋值给实体类。
- 遍历Map,通过Map的属性名称获取对应的实体类反射对象的属性对象,再赋值给实体类。
方法一
我们先来看第一种,遍历属性对象:
/**
* 将map转换成为对应的实体类
* @param objMap 需要转换的map
* @param clazz 转换实体类类型的反射对象
* @param <T> 泛型,反射对象对应的对象类型,也是最后返回的对象类型
* @return
*/
public static <T> T mapToEntity(HashMap<String, Object> objMap, Class<T> clazz) throws Exception {
// 创建实例对象
T instance = clazz.newInstance();
// 获取所有的属性对象
Field[] fields = clazz.getDeclaredFields();
// 遍历所有的属性对象
for (Field field : fields) {
// 私有属性访问授权
field.setAccessible(true);
// 获取属性名称
String name = field.getName();
// 从map中获取属性值
Object value = objMap.get(name);
// 给实例对象赋值
field.set(instance, value);
}
return instance;
}
测试一下:
/**
* @ClassName MapToEntity
* @Description 将map转换成实体类
* @Author 古阙月
* @Date 2020/9/18
* @Version 1.0
*/
public class MapToEntity2 {
public static void main(String[] args) throws Exception {
// 创建一个map,map的键名和实体类的属性名称一一对应
HashMap<String, Object> personMap = new HashMap();
personMap.put("name", "小小");
personMap.put("age", 17);
// 将map转换成对应的实体类
Person person = MyJson.mapToEntity(personMap, Person.class);
// 输出结果
System.out.println(person);
}
}
运行得:
转换成功!老铁,没毛病!!
方法二
我们再来看第二种方法,遍历Map:
/**
* TODO 当map中有实体类没有的字段时,会出异常,需要进行异常处理
* TODO 好处是:会给你提供警报
* TODO 坏处是:会给强迫症带来不适
* 将map转换成为对应的实体类
* @param objMap 需要转换的map
* @param clazz 转换实体类类型的反射对象
* @param <T> 泛型,反射对象对应的对象类型,也是最后返回的对象类型
* @return
*/
public static <T> T mapToEntity2(HashMap<String, Object> objMap, Class<T> clazz) throws Exception {
// 创建实例对象
T instance = clazz.newInstance();
// 遍历map
for (String key : objMap.keySet()) {
// 获取属性值
Object value = objMap.get(key);
try {
// 获取属性对象
Field field = clazz.getDeclaredField(key);
// 私有属性访问授权
field.setAccessible(true);
// 赋值
field.set(instance, value);
} catch (Exception e) {
e.printStackTrace();
}
}
return instance;
}
测试一下:
/**
* @ClassName MapToEntity
* @Description 将map转换成实体类
* @Author 古阙月
* @Date 2020/9/18
* @Version 1.0
*/
public class MapToEntity3 {
public static void main(String[] args) throws Exception {
// 创建一个map,map的键名和实体类的属性名称一一对应
HashMap<String, Object> personMap = new HashMap();
personMap.put("name", "小小");
personMap.put("age", 17);
// 将map转换成对应的实体类
Person person = MyJson.mapToEntity2(personMap, Person.class);
// 输出结果
System.out.println(person);
}
}
运动程序,查看控制台结果:
发现也非常完美。
那么这两种方法似乎都差不多,到底应该使用哪一种呢?请移步下一章节<小思考>
小思考
其实上述两种方法看似差不多,其实不然,让我们来把需要转换的Map来修改一下:
// 创建一个map,map的键名和实体类的属性名称一一对应
HashMap<String, Object> personMap = new HashMap();
personMap.put("name", "小小");
personMap.put("age", 17);
再给map添加一个键值对:
personMap.put("sex", "女");
运行第一种方法(遍历属性对象集合),得到结果:
结果和之前不变。其实也没什么问题,毕竟Person类中目前也没有sex这个属性。
我们再来看下第二种方法(遍历Map):
也是不影响结果的。但是这个时候,我们就会发现控制台会告诉我们实体类中不存在sex
这个属性。所以,我们可以很简单的得出结论:
- 第一种方法很舒适,不会报错。
- 第二种方法会给你报警,提醒你是不是实体类忘记添加了属性。
至于要用哪种,看你自己咯。
大思考
最后,我们再来一个大的总结:其实经过这样下来,我们似乎发现我们自己封装的工具方法,似乎更加简单。而阿里的Fastjson似乎更麻烦,还要用两个方法才能实现转换的功能。有些同学可能就要忍不住问阿里的工程师了:
但是如果你看了我的这篇博客,可能就会恍然大悟:
创作不易,各位客官,给个赞吧!