fastjson jsonobject 转bean失败_阿粉带你彻底解决开发中对象Bean与Map互转问题!

一、摘要

在实际开发过程中,经常碰到需要进行对象与map之间互转的问题,其实对于对象、Map 之间进行互转有很多种方式,下面我们一起来梳理一下:

  • 利用 JSON 工具包,将对象转成字符串,之后再转成 Map,这种需要转换2次,相对来说效率比较底;
  • 利用 Java 反射,获取 Bean 类的属性和值,再转换到 Map 对应的键值对中,相对来说这种方法效率高些,在实现上比较麻烦;
  • 利用 Java 的内省(Introspector) 实现,获取 Bean 类的属性和值,Map与对象互转,效率比较高;
  • 利用 apache 中的 BeanUtils工具包进行操作,底层实现类似方法三;
  • 利用net.sf.cglib.beans.BeanMap类中的方法,这种方式效率也非常高;

二、常用方法

也不多说了,直接show code,为了更接近实际场景,我们新建两个实体类UserRole,假设一个用户有多个角色,如下:

public class User {

private String userId;

private String userName;

private List roleList;//... 省略 setter 和 getterpublic User() {}public User(String userId, String userName) {this.userId = userId;this.userName = userName;
}
}
public class Role {

private String userId;

private String roleName;

//... 省略 setter 和 getter

public Role(String userId, String roleName) {
this.userId = userId;
this.roleName = roleName;
}
}
2.1、通过 JSON 进行转换

在这里,我们利用阿里巴巴的fastjson包进行转换,通过maven引入 jar,如下:

com.alibabafastjson1.2.49

方法如下:

public class BeanMapUtilByJson {

/**
* 对象转Map
* @param object
* @return
*/
public static Map beanToMap(Object object){
return JSONObject.parseObject(JSON.toJSONString(object),Map.class);
}

/**
* map转对象
* @param map
* @param beanClass
* @param
* @return
*/
public static T mapToBean(Map map, Class beanClass){return JSONObject.parseObject(JSON.toJSONString(map),beanClass);
}
}
2.2、利用反射进行转换

这种操作是利用 java 原生提供的反射特性来实现互转,方法如下:

public class BeanMapUtilByReflect {

/**
* 对象转Map
* @param object
* @return
* @throws IllegalAccessException
*/
public static Map beanToMap(Object object) throws IllegalAccessException {
Map map = new HashMap();
Field[] fields = object.getClass().getDeclaredFields();for (Field field : fields) {
field.setAccessible(true);
map.put(field.getName(), field.get(object));
}return map;
}/**
* map转对象
* @param map
* @param beanClass
* @param
* @return
* @throws Exception
*/public static T mapToBean(Map map, Class beanClass) throws Exception {
T object = beanClass.newInstance();
Field[] fields = object.getClass().getDeclaredFields();for (Field field : fields) {int mod = field.getModifiers();if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {continue;
}
field.setAccessible(true);if (map.containsKey(field.getName())) {
field.set(object, map.get(field.getName()));
}
}return object;
}
}
2.3、利用内省机制进行转换

内省(Introspector)是 Java 语言对 JavaBean 类属性、事件的一种缺省处理方法,也是基于 java 原生实现,操作如下:

public class BeanMapUtilByIntros {

/**
* 对象转Map
* @param object
* @return
*/
public static Map beanToMap(Object object) throws Exception {
Map map = new HashMap();
BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass());
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();for (PropertyDescriptor property : propertyDescriptors) {
String key = property.getName();if (key.compareToIgnoreCase("class") == 0) {continue;
}
Method getter = property.getReadMethod();
Object value = getter!=null ? getter.invoke(object) : null;
map.put(key, value);
}return map;
}/**
* map转对象
* @param map
* @param beanClass
* @param
* @return
* @throws Exception
*/public static T mapToBean(Map map, Class beanClass) throws Exception {
T object = beanClass.newInstance();
BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass());
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();for (PropertyDescriptor property : propertyDescriptors) {
Method setter = property.getWriteMethod();if (setter != null) {
setter.invoke(object, map.get(property.getName()));
}
}return object;
}
}
2.4、利用 apache 中的 BeanUtils 进行转换

在使用这个方法前,需要手动引入 apache 中的 beanutils 包,方法如下:

commons-beanutilscommons-beanutils1.9.3

想必大家都不会陌生,操作如下:

public class BeanMapUtilByApache {

/**
* 对象转Map
* @param object
* @return
*/
public static Map beanToMap(Object object){
return new org.apache.commons.beanutils.BeanMap(object);
}

/**
* map转对象
* @param map
* @param beanClass
* @param
* @return
*/
public static T mapToBean(Map map, Class beanClass) throws Exception {
T object = beanClass.newInstance();
org.apache.commons.beanutils.BeanUtils.populate(object, map);return object;
}
}
2.5、利用 cglib 中的 BeanMap 进行转换

在使用这个方法前,需要手动引入cglib 包,方法如下:

cglibcglib3.3.0

Spring 内置了 cglib,在项目中经常看到有同学用这个方法,操作如下:

public class BeanMapUtilByCglib {

/**
* 对象转Map
* @param object
* @return
*/
public static Map beanToMap(Object object){
Map map = new HashMap();if (object != null) {
BeanMap beanMap = BeanMap.create(object);for (Object key : beanMap.keySet()) {
map.put(key+"", beanMap.get(key));
}
}return map;
}/**
* map转对象
* @param map
* @param beanClass
* @param
* @return
* @throws Exception
*/public static T mapToBean(Map map, Class beanClass) throws Exception {
T bean = beanClass.newInstance();
BeanMap beanMap = BeanMap.create(bean);
beanMap.putAll(map);return bean;
}
}
2.6、测试

上面介绍完了操作,最后我们来测试一下,新建一个测试客户端TestClient,分别测试上面5个工具类

public class BeanMapClient {

/**
* 测试
* @param args
*/
public static void main(String[] args) {
//为了更贴近实际场景,构造嵌套实体对象
User user = new User("1","张三");
List roleList = new ArrayList();
roleList.add(new Role("1","技术经理"));
roleList.add(new Role("1","信息主任"));
user.setRoleList(roleList);//bean转map
Map userMap = BeanMapUtilByJson.beanToMap(user);
System.out.println("转换后的map:" + JSON.toJSONString(userMap));//修改源对象中信息
user.getRoleList().get(0).setRoleName("项目经理");
user.getRoleList().add(new Role("1","项目经理"));//map转bean
User newUser = BeanMapUtilByJson.mapToBean(userMap,User.class);
System.out.println("转换后的bean:" + JSON.toJSONString(newUser));
}
}

输出结果如下:

be7d3a6eb25d040fe347fdc6dbbc90fd.png

对上面5中输出结果进行分析,可以得出如下结论:

  • 将对象转换成map,基本都一致,将map转成bean的时候,有些小区别;
  • 方法一,通过json转换后的bean对象,即使源对象发生改变,转换后的对象不会发生变化,这是因为json在底层转换bean时,都创建了新的对象;
  • 方法二、三、四、五,当源对象有嵌套对象,修改嵌套对象,也就是Role内容,转换后的对象也会随之发生改变;

从结果可以看出,方法一、二、三、四、五,都可以进行对象与 map 的互转,那他们到底有啥区别呢?

下面我们从性能角度来观察一下,使用for循环测试 map 与对象的互转,结果如下:

934b755e7b6329b8a2b95fc1ae424b61.png

可能每个机器的性能不一样,这个是我的电脑上测试的结果,从数据上可以看出:

  • 性能最好的是反射方法,其次就是内省方法,这两个方法都没有引用第三方jar包,所以相对可能要快点;
  • 使用第三方引用中,cglib 效率还可以,其次 apache的beanUtils工具包,最后就是Json包;

三、总结

如果对性能要求很高,可以采用 java 原生编程实现对象与 map 的互转,如果已经引用了 apache 或者 cglib 的jar,可以利用它提供的方法进行转换,优先推荐使用 cglib,因为 Spring 已经继承了 cglib,在项目中可以直接使用!

< END >

如果大家喜欢我们的文章,欢迎大家转发,点击在看让更多的人看到。也欢迎大家热爱技术和学习的朋友加入的我们的知识星球当中,我们共同成长,进步。eb8ee33e019aff522b4c13055c6b1f0a.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值