map转Bean对象实用工具类(驼峰处理,时间格式等其他类型处理)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了map转Bean对象实用工具类(驼峰处理,时间格式等其他类型处理)相关的知识,希望对你有一定的参考价值。
参考技术A 在写一些复杂的查询时,JPA已经不满足我的要求了,然后就使用了jdbcTemplate,但是会面临一个问题,查询结果集是List<Map<String,Object>>,还需转换到我对应的实体类,属性一个个拿出来再赋值实在太累,所以写一个工具类方便以后转换首先看下我遇到的问题以及处理方案,方便大家理解。
这样使用jdbcTemplate查询转对象就非常方便啦,又可以愉快的使用JPA开发项目了。
对象Bean与Map互转问题
一、摘要
在实际开发过程中,经常碰到需要进行对象与map之间互转的问题,其实对于对象、Map 之间进行互转有很多种方式,下面我们一起来梳理一下:
- 利用 JSON 工具包,将对象转成字符串,之后再转成 Map,这种需要转换2次,相对来说效率比较底;
- 利用 Java 反射,获取 Bean 类的属性和值,再转换到 Map 对应的键值对中,相对来说这种方法效率高些,在实现上比较麻烦;
- 利用 Java 的内省(Introspector) 实现,获取 Bean 类的属性和值,Map与对象互转,效率比较高;
- 利用 apache 中的
BeanUtils
工具包进行操作,底层实现类似方法三; - 利用
net.sf.cglib.beans.BeanMap
类中的方法,这种方式效率也非常高;
二、常用方法
也不多说了,直接show code
,为了更接近实际场景,我们新建两个实体类User
、Role
,假设一个用户有多个角色,如下:
publicclass User { private String userId; private String userName; private List<Role> roleList; //... 省略 setter 和 getter public User() {} public User(String userId, String userName) { this.userId = userId; this.userName = userName; } } publicclass 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,如下:
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.49</version> </dependency>
方法如下:
publicclass 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 <T> * @return */ publicstatic <T> T mapToBean(Map map, Class<T> beanClass){ return JSONObject.parseObject(JSON.toJSONString(map),beanClass); } }
2.2、利用反射进行转换
这种操作是利用 java 原生提供的反射特性来实现互转,方法如下:
publicclass BeanMapUtilByReflect { /** * 对象转Map * @param object * @return * @throws IllegalAccessException */ public static Map beanToMap(Object object) throws IllegalAccessException { Map<String, Object> map = new HashMap<String, Object>(); 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 <T> * @return * @throws Exception */ publicstatic <T> T mapToBean(Map map, Class<T> 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 原生实现,操作如下:
publicclass BeanMapUtilByIntros { /** * 对象转Map * @param object * @return */ public static Map beanToMap(Object object) throws Exception { Map<String, Object> map = new HashMap<String, Object>(); 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 <T> * @return * @throws Exception */ publicstatic <T> T mapToBean(Map map, Class<T> 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 包,方法如下:
<dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.9.3</version> </dependency>
想必大家都不会陌生,操作如下:
publicclass BeanMapUtilByApache { /** * 对象转Map * @param object * @return */ public static Map beanToMap(Object object){ returnnew org.apache.commons.beanutils.BeanMap(object); } /** * map转对象 * @param map * @param beanClass * @param <T> * @return */ publicstatic <T> T mapToBean(Map map, Class<T> beanClass) throws Exception { T object = beanClass.newInstance(); org.apache.commons.beanutils.BeanUtils.populate(object, map); return object; } }
2.5、利用 cglib 中的 BeanMap 进行转换
在使用这个方法前,需要手动引入cglib 包,方法如下:
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency>
Spring 内置了 cglib,在项目中经常看到有同学用这个方法,操作如下:
publicclass BeanMapUtilByCglib { /** * 对象转Map * @param object * @return */ public static Map beanToMap(Object object){ Map<String, Object> map = new HashMap<String, Object>(); 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 <T> * @return * @throws Exception */ publicstatic <T> T mapToBean(Map map, Class<T> beanClass) throws Exception { T bean = beanClass.newInstance(); BeanMap beanMap = BeanMap.create(bean); beanMap.putAll(map); return bean; } }
2.6、测试
上面介绍完了操作,最后我们来测试一下,新建一个测试客户端TestClient
,分别测试上面5个工具类
publicclass BeanMapClient { /** * 测试 * @param args */ public static void main(String[] args) { //为了更贴近实际场景,构造嵌套实体对象 User user = new User("1","张三"); List<Role> roleList = new ArrayList<Role>(); 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)); } }
输出结果如下:
对上面5中输出结果进行分析,可以得出如下结论:
- 将对象转换成map,基本都一致,将map转成bean的时候,有些小区别;
- 方法一,通过json转换后的bean对象,即使源对象发生改变,转换后的对象不会发生变化,这是因为json在底层转换bean时,都创建了新的对象;
- 方法二、三、四、五,当源对象有嵌套对象,修改嵌套对象,也就是
Role
内容,转换后的对象也会随之发生改变;
从结果可以看出,方法一、二、三、四、五,都可以进行对象与 map 的互转,那他们到底有啥区别呢?
下面我们从性能角度来观察一下,使用for
循环测试 map 与对象的互转,结果如下:
可能每个机器的性能不一样,这个是我的电脑上测试的结果,从数据上可以看出:
- 性能最好的是反射方法,其次就是内省方法,这两个方法都没有引用第三方jar包,所以相对可能要快点;
- 使用第三方引用中,cglib 效率还可以,其次 apache的beanUtils工具包,最后就是Json包;
三、总结
如果对性能要求很高,可以采用 java 原生编程实现对象与 map 的互转,如果已经引用了 apache 或者 cglib 的jar,可以利用它提供的方法进行转换,优先推荐使用 cglib,因为 Spring 已经继承了 cglib,在项目中可以直接使用!
原文链接:https://mp.weixin.qq.com/s/6dq6aKfV1GKLOvD-RGmcpw
以上是关于map转Bean对象实用工具类(驼峰处理,时间格式等其他类型处理)的主要内容,如果未能解决你的问题,请参考以下文章