目录
- 方案一: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
方案三:MapStruct
方案四:Orika
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
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);
}
}