对象Bean与Map互转,是经常遇到的场景。当然这个是属于复杂 Bean 对象了,比如组合实体类的嵌套,本文构建测试实例,记录并总结相关解决办法,代码地址:https://github.com/hkdijia/objectConverts.git --dev 分支

转换方法

大致分成两类,基于 JDK :

  1. 利用 Java 的内省(Introspector) 实现,获取 Bean 类的属性和值,Map与对象互转,效率比较高;
  2. 利用 Java 反射,获取 Bean 类的属性和值,再转换到 Map 对应的键值对中,相对来说这种方法效率高些,在实现上比较麻烦;

基于第三方工具包的实现:

  1. 利用 JSON 工具包,将对象转成字符串,之后再转成 Map,这种需要转换2次,相对来说效率比较低;
  2. 利用 apache 中的 BeanUtils工具包进行操作,底层实现类似方法1;
  3. 利用net.sf.cglib.beans.BeanMap类中的方法,这种方式效率也非常高;

编码

基础 POJO

我们模拟 RBAC 关系模型中的,用户-角色 一对多关系

public class Role {
    String roleCode;
    String roleName;
}

/*	省略get set 和 构造方法 和 toString	*/

public class User {
    String userId;
    String userName;
    List<Role> roleList;
}

/*	省略get set 和 构造方法 和 toString	*/

实现的具体结果,是工具类

内省实现

package com.gotkx.introspector;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;


/**
 * 内省机制
 * @author HuangKai
 *
 */
public class 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
     */
    public static <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;
    }

}

反射实现


package com.gotkx.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

/**
 * 反射实现
 * @author HuangKai
 */
public class 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
     */
    public static <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;
    }

}


FastJSON 转换实现


package com.gotkx.fastjson;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import java.util.Map;

/**
 * FastJSON 进行转换
 * @author HuangKai
 */
public class BeanMapUtilByFastJson {

    /**
     * 对象转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
     */
    public static <T> T mapToBean(Map map, Class<T> beanClass){
        return JSONObject.parseObject(JSON.toJSONString(map),beanClass);
    }

}

Apache 中的 BeanUtils 实现


package com.gotkx.beanUtils;

import java.util.Map;

/**
 * Apache 中的 BeanUtils 实现
 * @author HuangKai
 */
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 <T>
     * @return
     */
    public static <T> T mapToBean(Map map, Class<T> beanClass) throws Exception {
        T object = beanClass.newInstance();
        org.apache.commons.beanutils.BeanUtils.populate(object, map);
        return object;
    }

}

cglib 中的 BeanMap 实现


package com.gotkx.beanMap;

import net.sf.cglib.beans.BeanMap;

import java.util.HashMap;
import java.util.Map;

/**
 * cglib 中的 BeanMap 实现
 * @author HuangKai
 */
public class 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
     */
    public static <T> T mapToBean(Map map, Class<T> beanClass) throws Exception {
        T bean = beanClass.newInstance();
        BeanMap beanMap = BeanMap.create(bean);
        beanMap.putAll(map);
        return bean;
    }

}



测试用例

测试用例都在代码里面,自行运行吧,我就不 PO 出了

map 和 object 互转总结构.png.png

优缺点

  • 缺点:如从 Map 转 Object,类型不一样,是会存在 Cast 异常的
  • 优点:如从 Map 转 Object,可以放置超过 Object 属性的 key-value 值的

性能对比

这里就不进行压测了,公认的结论如下:

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