Map集合转为实体对象

源码:https://gitee.com/Jakewabc/small-study-case/blob/master/nm-demo/mongodb-demo/src/main/java/com/mongodb/utils/ObjectIdJsonSerializer.java

使用MongoDB朋友都明白,如果我们使用连集合查询的时候需要使用聚合。但是聚合查询有个特点,我们实体类里面的 id字段会保存在MongoDB中会做 _id。但是如果使用聚合查询时,返回给我们的字段依然是 _id而不是 id。但是返回来的是一个Map集合,从表我们可以根据自己定义的kay直接从Map集合中获取做一个强转是没有问题的。但是主表有多少个字段就在MongoDB返回的这个Map集合中就有多少个key。总不能让我们一个字段一个字段的去取出来存入对象吧,所以使用反射写一个工具类,直接调用即可将Map集合转为实体对象。

package com.centre.common.utils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 将Map集合转为对象
 * <p>
 *     使用范例:
 *     public static void main(String[] args) throws Exception {
 *         Map<String,Object> map = new HashMap<>();
 *         map.put("id",12346546l);
 *         map.put("name","比亚迪,长安");
 *         map.put("manufactor","比亚迪厂家,长安厂家");
 *         map.put("dateOfManufacture",new Date());
 *
 *         HandleMapToObject<CarDO> toObject = new HandleMapToObject<CarDO>();
 *         CarDO carDO = toObject.mapToObject(map, CarDO.class,true);
 *         System.out.println(carDO);
 *         // 输出结果:CarDO(id=12346546, name=比亚迪,长安, manufactor=比亚迪厂家,长安厂家, dateOfManufacture=Thu Mar 11 00:41:32 CST 2021)
 *     }
 * </p>
 * @Author: Stars
 * @Date: 2021/3/10 22:06
 */
public class HandleMapToObject<T> {

    /**
     * 将Map集合转为实体对象
     * @param map Map集合
     * @param t 转换后的对象
     * @param considerThread true:考虑现成安全,false:不考虑
     * @return
     * @throws Exception
     */
    private T mapToObject(Map map, Class<T> t,Boolean considerThread) throws Exception {
        Class<?> clazz = null;
        if (considerThread) {
            //通过类装载器获取t类对象
            ClassLoader loader = Thread.currentThread().getContextClassLoader();
            clazz = loader.loadClass(Class.forName(t.getName()).getName());
        } else {
            clazz = Class.forName(Class.forName(t.getName()).getName());
        }
        //获取类的默认构造器对象并通过它实例化t
        Constructor cons = clazz.getDeclaredConstructor((Class[]) null);
        T t1 = (T) cons.newInstance();
        // 获取t对象的所有属性
        Field[] fields = clazz.getDeclaredFields();
        // 将t对象中属性保存为Map的key值,数据类型保存为value值
        Map<String, Object> fieldMap = Arrays.stream(fields).collect(Collectors.toMap(Field::getName, Field::getType));
        // 取出map集合中的全部数据
        Class<?> finalClazz = clazz;
        map.forEach((k, v) -> {
            try {
                // 给当前属性赋值,本来数据类型应该fieldMap.get(k).getClass()这样写。但是上面获取t对象的数据类型时Field::getType这种方法应用不能再获取getName()属性,所以这里是class java.lang.String的类型了,不能再点getClass()了。     所有强转了一下。(Class) fieldMap.get(k)
                Method setBrand = finalClazz.getMethod(initcap(String.valueOf(k)), (Class) fieldMap.get(k));
                setBrand.invoke(t1, v);
            } catch (Exception e) {
                System.out.println("map集合转数组异常:"+t.getClass());
            }
        });
        return t1;
    }

    /***
     * 将对象属性转为set方法名
     * @param str 转大写的字符串
     * @return
     */
    public static String initcap(String str) {
        return "set" + str.substring(0, 1).toUpperCase() + str.substring(1) ;
    }
}

  • 实现思路

Map集合名为为map和实体对象类型传入。创建一个Map集合保存对象的属性和数类型,Map集合名为fieldMap,因为反射赋值时需要使用对象属性和属性类型。将对象的属性保存为fieldMap集合的key,数据类型保存为fieldMap集合的value。然后循环map集合,因为MongoDB返回来的这个map集合的key就是对象的属性名。所以循环map集合,取出key值到fieldMap集合中获取数类型。现在属性名、数据类型和保存的数据都知道了,接下来的事情就是水到渠成了。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐