目录

  • 方案一:Cglib BeanCopier
  • 方案二:Spring BeanUtils
  • 方案三:MapStruct
  • 方案四:Orika
  • 方案五:Dozer


方案一:Cglib BeanCopier

import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.cglib.beans.BeanMap;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 创建对象copy工具类 复制对象采用cglib beanCopier, cglib性能高于spring BeanUtils
 * 注意:当被复制的实体类使用lombok @Accessors(chain = true)注解时 使用BeanUtil.copy方法失败,请使用 org.springframework.beans.BeanUtils.copyProperties 方法
 *
 * @author zhaoyang10
 * @date 2018/10/25
 */
@Slf4j
public class BeanUtil {

    private BeanUtil() {
    }

    /**
     * 缓存copier
     */
    private static final Map<String, BeanCopier> BEAN_COPIERS = new ConcurrentHashMap<>();

    /**
     * 对象复制
     *
     * @param source 源对象-被复制的对象
     * @param target 目标对象-新对象
     * @author zhaoyang10
     */
    public static void copy(Object source, Object target) {
        String beanKey = generateKey(source.getClass(), target.getClass());
        BeanCopier copier;
        if (!BEAN_COPIERS.containsKey(beanKey)) {
            copier = BeanCopier.create(source.getClass(), target.getClass(), false);
            BEAN_COPIERS.put(beanKey, copier);
        } else {
            copier = BEAN_COPIERS.get(beanKey);
        }
        copier.copy(source, target, null);
    }

    private static String generateKey(Class<?> sourceClass, Class<?> targetClass) {
        return sourceClass.getName() + ":" + targetClass.getName();
    }

    /**
     * 将对象装换为map
     */
    @SuppressWarnings("unchecked")
    public static Map<String, Object> beanToMap(Object bean) {
        return BeanMap.create(bean);
    }

    /**
     * 将map装换为javabean对象
     */
    public static <T> T mapToBean(Map<String, Object> map, T bean) {
        BeanMap beanMap = BeanMap.create(bean);
        beanMap.putAll(map);
        return bean;
    }

    /**
     * 将List<T>转换为List<Map<String, Object>>
     */
    public static <T> List<Map> objectsToMaps(List<T> objList) {
        List<Map> list = Lists.newArrayList();
        if (objList != null && !objList.isEmpty()) {
            Map map;
            for (Object item : objList) {
                map = beanToMap(item);
                list.add(map);
            }
        }
        return list;
    }

    /**
     * 将List<Map<String,Object>>转换为List<T>
     */
    public static <T> List<T> mapsToObjects(List<Map<String, Object>> maps, Class<T> clazz) {
        try {
            List<T> list = Lists.newArrayList();
            if (maps != null && !maps.isEmpty()) {
                T bean;
                for (Map<String, Object> item : maps) {
                    bean = clazz.newInstance();
                    mapToBean(item, bean);
                    list.add(bean);
                }
            }
            return list;
        } catch (Exception e) {
            log.error("转换出错", e);
            return Collections.emptyList();
        }
    }

    /**
     * 通过对象属性名获取对象中的属性值
     */
    public static Object getProp(Object object, String name) {
        if (object == null || name == null || "".equals(name.trim())) {
            return null;
        }
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                String tempName = property.getName();

                if (name.equals(tempName)) {
                    Method getter = property.getReadMethod();
                    Object value = null;
                    if (getter != null) {
                        value = getter.invoke(object);
                    }
                    return value;
                }
            }
        } catch (Exception e) {
            log.error("getProp出错", e);
        }
        return null;
    }

}

方案二:Spring BeanUtils

改造BeanUtils优雅实现高频工具类!

方案三:MapStruct

Github 官网

MapStruct使用教程

Java 实体映射工具 MapStruct

方案四:Orika

SpringBoot 如何进行对象复制

OrikaUtils.java 封装工具类

import ma.glasnost.orika.MapperFacade;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import ma.glasnost.orika.metadata.ClassMapBuilder;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Orika封装的工具类
 */
public class OrikaUtils {

    private static final MapperFactory FACTORY = new DefaultMapperFactory.Builder().build();

    /**
     * 缓存实例集合
     */
    private static final Map<String, MapperFacade> CACHE_MAPPER = new ConcurrentHashMap<>();

    private final MapperFacade mapper;

    public OrikaUtils(MapperFacade mapper) {
        this.mapper = mapper;
    }

    /**
     * 转换实体函数
     * @param sourceEntity 源实体
     * @param targetClass  目标类对象
     * @param refMap       配置源类与目标类不同字段名映射
     * @param <S>          源泛型
     * @param <T>          目标泛型
     * @return 目标实体
     */
    public static <S, T> T convert(S sourceEntity, Class<T> targetClass, Map<String, String> refMap) {
        if (sourceEntity == null) {
            return null;
        }
        return classMap(sourceEntity.getClass(), targetClass, refMap).map(sourceEntity, targetClass);
    }

    /**
     * 转换实体函数
     *
     * @param sourceEntity 源实体
     * @param targetClass  目标类对象
     * @param <S>          源泛型
     * @param <T>          目标泛型
     * @return 目标实体
     */
    public static <S, T> T convert(S sourceEntity, Class<T> targetClass) {
        return convert(sourceEntity, targetClass, null);
    }

    /**
     * 转换实体集合函数
     *
     * @param sourceEntityList 源实体集合
     * @param targetClass      目标类对象
     * @param refMap           配置源类与目标类不同字段名映射
     * @param <S>              源泛型
     * @param <T>              目标泛型
     * @return 目标实体集合
     */
    public static <S, T> List<T> convertList(List<S> sourceEntityList, Class<T> targetClass, Map<String, String> refMap) {
        if (sourceEntityList == null) {
            return null;
        }
        if (sourceEntityList.size() == 0) {
            return new ArrayList<>(0);
        }
        return classMap(sourceEntityList.get(0).getClass(), targetClass, refMap).mapAsList(sourceEntityList, targetClass);
    }

    /**
     * 转换实体集合函数
     *
     * @param sourceEntityList 源实体集合
     * @param targetClass      目标类对象
     * @param <S>              源泛型
     * @param <T>              目标泛型
     * @return 目标实体集合
     */
    public static <S, T> List<T> convertList(List<S> sourceEntityList, Class<T> targetClass) {
        return convertList(sourceEntityList, targetClass, null);
    }



    /**
     * 注册属性
     * @param source 源类
     * @param target 目标类
     * @param refMap 属性转换
     */
    public static <V, P> void register(Class<V> source, Class<P> target,Map<String, String> refMap){
        if (CollectionUtils.isEmpty(refMap)) {
            FACTORY.classMap(source, target).byDefault().register();
        } else {
            ClassMapBuilder<V, P> classMapBuilder = FACTORY.classMap(source, target);
            refMap.forEach(classMapBuilder::field);
            classMapBuilder.byDefault().register();
        }
    }

    /**
     * 属性名称一致可用
     * @param source 源数据
     * @param target 目标对象
     * @return OrikaUtils
     */
    private static <V, P> OrikaUtils classMap(Class<V> source, Class<P> target) {
        return classMap(source, target, null);
    }

    /**
     * 属性名称不一致可用
     *
     * @param source 原对象
     * @param target 目标对象
     * @return OrikaUtils
     */
    private static synchronized <V, P> OrikaUtils classMap(Class<V> source, Class<P> target, Map<String, String> refMap) {
        String key = source.getCanonicalName() + ":" + target.getCanonicalName();
        if (CACHE_MAPPER.containsKey(key)) {
            return new OrikaUtils(CACHE_MAPPER.get(key));
        }
        register(source,target,refMap);
        MapperFacade mapperFacade = FACTORY.getMapperFacade();
        CACHE_MAPPER.put(key, mapperFacade);

        return new OrikaUtils(mapperFacade);
    }



    /**
     * Orika复制对象
     * @param source 源数据
     * @param target 目标对象
     * @return target
     */
    private <V, P> P map(V source, Class<P> target) {
        return mapper.map(source, target);
    }

    /**
     * 复制List
     * @param source 源对象
     * @param target 目标对象
     * @return P
     */
    private <V, P> List<P> mapAsList(List<V> source, Class<P> target) {
        return CollectionUtils.isEmpty(source) ? Collections.emptyList() : mapper.mapAsList(source, target);
    }

}

方案五:Dozer

Github 官网

Dozer使用教程

Dozer 工具类

import java.util.Collection;
import java.util.List;

import org.dozer.DozerBeanMapper;

import com.google.common.collect.Lists;

/**
 * 简单封装Dozer, 实现深度转换Bean<->Bean的Mapper.实现:
 *  
 * 1. 持有Mapper的单例. 
 * 2. 返回值类型转换.
 * 3. 批量转换Collection中的所有对象.
 * 4. 区分创建新的B对象与将对象A值复制到已存在的B对象两种函数.
 */
public class BeanMapper {

	/**
	 * 持有Dozer单例, 避免重复创建DozerMapper消耗资源.
	 */
	private static DozerBeanMapper dozer = new DozerBeanMapper();

	/**
	 * 基于Dozer转换对象的类型.
	 */
	public static <T> T map(Object source, Class<T> destinationClass) {
		return dozer.map(source, destinationClass);
	}

	/**
	 * 基于Dozer转换Collection中对象的类型.
	 */
	@SuppressWarnings("rawtypes")
	public static <T> List<T> mapList(Collection sourceList, Class<T> destinationClass) {
		List<T> destinationList = Lists.newArrayList();
		for (Object sourceObject : sourceList) {
			T destinationObject = dozer.map(sourceObject, destinationClass);
			destinationList.add(destinationObject);
		}
		return destinationList;
	}

	/**
	 * 基于Dozer将对象A的值拷贝到对象B中.
	 */
	public static void copy(Object source, Object destinationObject) {
		dozer.map(source, destinationObject);
	}
}