package com.book.common.utils;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.book.common.function.CurrentFunction;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import java.beans.PropertyDescriptor;
import java.lang.reflect.*;
import java.math.BigDecimal;
import java.util.*;
/**
* Description:
* <p>
* 通过JSON字符串实现
* 对象转Map
* Map转对象
* </p>
*
* @Author: leo.xiong
* @CreateDate: 2022/12/7 11:56
* @Email: leo.xiong@suyun360.com
* @Since:
*/
@Slf4j
public class BeanCopyUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(BeanCopyUtil.class);
/**
* 根据类缓存某个属性是否直接复制
*/
private static final Map<Class, Map<String, FieldCanCopy>> FIELD_COPY_CACHE = Maps.newConcurrentMap();
/**
* 直接赋值
*/
public static final int DIRECT_ASSIGNMENT = 1;
/**
* 转换赋值
*/
public static final int TRANSFORM_ASSIGNMENT = 2;
public static String toJSONString(List<Map> mapList) {
return JSONObject.toJSONString(mapList);
}
public static String toJSONString(Map map) {
return JSONObject.toJSONString(map);
}
/**
* List<Bean>转List<Map>
*
* @param objectList
* @return
*/
public static List<Map> beanToMapList(List<Object> objectList) {
if (CollectionUtils.isEmpty(objectList)) {
return Collections.EMPTY_LIST;
}
List<Map> list = Lists.newArrayListWithExpectedSize(objectList.size());
for (Object obj : objectList) {
list.add(beanToMap(obj));
}
return list;
}
/**
* Bean转Map
*
* @param object
* @return
* @throws IllegalAccessException
*/
public static Map beanToMap(Object object) {
if (object == null) {
return null;
}
Map<String, String> map = Maps.newHashMap();
Field[] fields = object.getClass().getDeclaredFields();
for (Field field : fields) {
boolean isAccessible = field.isAccessible();
try {
field.setAccessible(true);
Object value = field.get(object);
if (value == null) {
map.put(field.getName(), null);
} else if (value instanceof Date) {
//时间都转为年月日时分秒,使用是可以具体处理
map.put(field.getName(), DatetimeUtil.formatDate((Date) value, DatetimeUtil.YYYY_MM_DD_HH_MM_SS_L_C));
} else if (value.getClass().isArray() || value instanceof Collection || value instanceof Map) {
//集合数组类型先转为JSON字符串,注意循环引用问题,默认使用$rel对重复和递归引用,反序列化获取不到对应的值
map.put(field.getName(), JSONObject.toJSONString(value, SerializerFeature.DisableCircularReferenceDetect));
} else {
map.put(field.getName(), String.valueOf(value));
}
} catch (IllegalAccessException e) {
LOGGER.warn("属性获取失败 type: {} name: {}", field.getType(), field.getName(), e);
map.put(field.getName(), null);
} finally {
field.setAccessible(isAccessible);
}
}
return map;
}
/**
* List<Map>转List<Bean>
*
* @param nameValueMapList
* @param clazz
* @param <T>
* @return
*/
public static <T> List<T> mapToBeanList(List<Map> nameValueMapList, Class<T> clazz) {
if (CollectionUtils.isEmpty(nameValueMapList)) {
return Collections.EMPTY_LIST;
}
List<T> valueList = Lists.newArrayListWithExpectedSize(nameValueMapList.size());
for (Map nameValueMap : nameValueMapList) {
valueList.add(mapToBean(nameValueMap, clazz));
}
return valueList;
}
/**
* Map转Bean
*
* @param nameValueMap
* @param clazz
* @param <T>
* @return
*/
public static <T> T mapToBean(Map nameValueMap, Class<T> clazz) {
if (CollectionUtils.isEmpty(nameValueMap) || clazz == null) {
return null;
}
T t = null;
try {
t = clazz.getDeclaredConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
e.printStackTrace();
return null;
}
Field[] fields = clazz.getDeclaredFields();
Method[] methods = clazz.getDeclaredMethods();
Map<String, Method> methodNameMethodMap = Maps.newHashMapWithExpectedSize(methods.length);
for (Method method : methods) {
methodNameMethodMap.put(method.getName().toLowerCase(), method);
}
for (Field field : fields) {
Class<?> type = field.getType();
String propertyName = field.getName();
String value = (String) nameValueMap.get(propertyName);
if (StringUtils.isEmpty(value)) {
continue;
}
Method method = methodNameMethodMap.get("set" + propertyName.toLowerCase());
if (method == null) {
continue;
}
boolean isAccessible = method.isAccessible();
try {
method.setAccessible(true);
if (isBasicClass(type)) {
method.invoke(t, getCommonDataTypeValue(type, value));
} else if (type.isArray()) {
Class<?> childrenType = getCommonDataType(type);
if (childrenType == null) {
//数组里对象是自定义对象不做处理,可以引入Function处理
continue;
}
JSONArray jsonArray = JSONObject.parseArray(value);
method.invoke(t, buildArray(childrenType, jsonArray));
} else if (Collection.class.isAssignableFrom(type) || Map.class.isAssignableFrom(type)) {
try {
Map values = JSONObject.parseObject(value, Map.class);
method.invoke(t, values);
continue;
} catch (Exception e) {
}
Type[] childrenType = method.getGenericParameterTypes();
ParameterizedType pType = (ParameterizedType) childrenType[0];
Object objValue = null;
try {
objValue = Class.forName(pType.getActualTypeArguments()[0].getTypeName()).newInstance();
} catch (Exception e) {
}
//获取泛型属性
if (objValue == null) {
continue;
}
List valuesList = JSONObject.parseArray(value, objValue.getClass());
if (pType.getRawType().toString().endsWith("List")) {
method.invoke(t, valuesList);
} else if (pType.getRawType().toString().endsWith("Set")) {
method.invoke(t, Sets.newHashSet(valuesList));
}
} else {
method.invoke(t, mapToBean(nameValueMap, clazz));
}
} catch (Exception e) {
LOGGER.warn("属性设置失败 type: {} name: {}", field.getType(), field.getName(), e);
} finally {
method.setAccessible(isAccessible);
}
}
return t;
}
private static Object getCommonDataTypeValue(Class<?> type, String value) {
if (type == Boolean.class || type.getName().toLowerCase().contains(Boolean.class.getSimpleName().toLowerCase())) {
return Boolean.valueOf(value);
} else if (type == Byte.class || type.getName().toLowerCase().contains(Byte.class.getSimpleName().toLowerCase())) {
return Byte.valueOf(value);
} else if (type == Short.class || type.getName().toLowerCase().contains(Short.class.getSimpleName().toLowerCase())) {
return Short.valueOf(value);
} else if (type == Integer.class || type.getName().toLowerCase().contains(int.class.getSimpleName().toLowerCase())) {
return Integer.valueOf(value);
} else if (type == Long.class || type.getName().toLowerCase().contains(Long.class.getSimpleName().toLowerCase())) {
return Long.valueOf(value);
} else if (type == Float.class || type.getName().toLowerCase().contains(Float.class.getSimpleName().toLowerCase())) {
return Float.valueOf(value);
} else if (type == Double.class || type.getName().toLowerCase().contains(Double.class.getSimpleName().toLowerCase())) {
return Double.valueOf(value);
} else if (type == Character.class || type.getName().toLowerCase().contains(char.class.getSimpleName().toLowerCase())) {
return value.toCharArray()[0];
} else if (type == String.class || type.getName().toLowerCase().contains(String.class.getSimpleName().toLowerCase())) {
return value;
} else if (type == BigDecimal.class || type.getName().toLowerCase().contains(BigDecimal.class.getSimpleName().toLowerCase())) {
return new BigDecimal(value);
} else if (type == Date.class || type.getName().toLowerCase().contains(Date.class.getSimpleName().toLowerCase())) {
try {
return DatetimeUtil.changeToDate(value);
} catch (Exception e) {
log.warn("时间格式化不对 value: {}", value);
}
}
return null;
}
private static Class<?> getCommonDataType(Class<?> type) {
return getCommonDataType(type, type.getName());
}
private static Class<?> getCommonDataType(Class<?> type, String className) {
if (type == Boolean.class || className.toLowerCase().contains(Boolean.class.getSimpleName().toLowerCase())) {
return Boolean.class;
} else if (type == Byte.class || className.toLowerCase().contains(Byte.class.getSimpleName().toLowerCase())) {
return Byte.class;
} else if (type == Short.class || className.toLowerCase().contains(Short.class.getSimpleName().toLowerCase())) {
return Short.class;
} else if (type == Integer.class || className.toLowerCase().contains(int.class.getSimpleName().toLowerCase())) {
return Integer.class;
} else if (type == Long.class || className.toLowerCase().contains(Long.class.getSimpleName().toLowerCase())) {
return Long.class;
} else if (type == Float.class || className.toLowerCase().contains(Float.class.getSimpleName().toLowerCase())) {
return Float.class;
} else if (type == Double.class || className.toLowerCase().contains(Double.class.getSimpleName().toLowerCase())) {
return Double.class;
} else if (type == Character.class || className.toLowerCase().contains(char.class.getSimpleName().toLowerCase())) {
return Character.class;
} else if (type == String.class || className.toLowerCase().contains(String.class.getSimpleName().toLowerCase())) {
return String.class;
} else if (type == BigDecimal.class || className.toLowerCase().contains(BigDecimal.class.getSimpleName().toLowerCase())) {
return BigDecimal.class;
} else if (type == Date.class || className.toLowerCase().contains(Date.class.getSimpleName().toLowerCase())) {
return Date.class;
}
return null;
}
private static Object buildArray(Class<?> type, JSONArray jsonArray) {
if (type == Boolean.class || type.getName().toLowerCase().contains(Boolean.class.getSimpleName().toLowerCase())) {
Boolean[] booleans = new Boolean[jsonArray.size()];
for (int i = 0; i < jsonArray.size(); i++) {
booleans[i] = (Boolean) getCommonDataTypeValue(type, jsonArray.get(i).toString());
}
return booleans;
} else if (type == Byte.class || type.getName().toLowerCase().contains(Byte.class.getSimpleName().toLowerCase())) {
Byte[] bytes = new Byte[jsonArray.size()];
for (int i = 0; i < jsonArray.size(); i++) {
bytes[i] = (Byte) getCommonDataTypeValue(type, jsonArray.get(i).toString());
}
return bytes;
} else if (type == Short.class || type.getName().toLowerCase().contains(Short.class.getSimpleName().toLowerCase())) {
Short[] shorts = new Short[jsonArray.size()];
for (int i = 0; i < jsonArray.size(); i++) {
shorts[i] = (Short) getCommonDataTypeValue(type, jsonArray.get(i).toString());
}
return shorts;
} else if (type == Integer.class || type.getName().toLowerCase().contains(int.class.getSimpleName().toLowerCase())) {
Integer[] integers = new Integer[jsonArray.size()];
for (int i = 0; i < jsonArray.size(); i++) {
integers[i] = (Integer) getCommonDataTypeValue(type, jsonArray.get(i).toString());
}
return integers;
} else if (type == Long.class || type.getName().toLowerCase().contains(Long.class.getSimpleName().toLowerCase())) {
Long[] longs = new Long[jsonArray.size()];
for (int i = 0; i < jsonArray.size(); i++) {
longs[i] = (Long) getCommonDataTypeValue(type, jsonArray.get(i).toString());
}
return longs;
} else if (type == Float.class || type.getName().toLowerCase().contains(Float.class.getSimpleName().toLowerCase())) {
Float[] floats = new Float[jsonArray.size()];
for (int i = 0; i < jsonArray.size(); i++) {
floats[i] = (Float) getCommonDataTypeValue(type, jsonArray.get(i).toString());
}
return floats;
} else if (type == Double.class || type.getName().toLowerCase().contains(Double.class.getSimpleName().toLowerCase())) {
Double[] doubles = new Double[jsonArray.size()];
for (int i = 0; i < jsonArray.size(); i++) {
doubles[i] = (Double) getCommonDataTypeValue(type, jsonArray.get(i).toString());
}
return doubles;
} else if (type == Character.class || type.getName().toLowerCase().contains(char.class.getSimpleName().toLowerCase())) {
Character[] characters = new Character[jsonArray.size()];
for (int i = 0; i < jsonArray.size(); i++) {
characters[i] = (Character) getCommonDataTypeValue(type, jsonArray.get(i).toString());
}
return characters;
} else if (type == String.class || type.getName().toLowerCase().contains(String.class.getSimpleName().toLowerCase())) {
String[] strings = new String[jsonArray.size()];
for (int i = 0; i < jsonArray.size(); i++) {
strings[i] = (String) getCommonDataTypeValue(type, jsonArray.get(i).toString());
}
return strings;
} else if (type == BigDecimal.class || type.getName().toLowerCase().contains(BigDecimal.class.getSimpleName().toLowerCase())) {
BigDecimal[] bigDecimals = new BigDecimal[jsonArray.size()];
for (int i = 0; i < jsonArray.size(); i++) {
bigDecimals[i] = (BigDecimal) getCommonDataTypeValue(type, jsonArray.get(i).toString());
}
return bigDecimals;
} else if (type == Date.class || type.getName().toLowerCase().contains(Date.class.getSimpleName().toLowerCase())) {
Date[] dates = new Date[jsonArray.size()];
for (int i = 0; i < jsonArray.size(); i++) {
dates[i] = (Date) getCommonDataTypeValue(type, jsonArray.get(i).toString());
}
return dates;
}
return null;
}
/**
* 判断是否是基础数据类型,即 int,double,long等类似格式
*/
public static boolean isCommonDataType(Class clazz) {
return clazz.isPrimitive();
}
/**
* 判断是否是基础数据类型的包装类型
*
* @param clz
* @return
*/
public static boolean isWrapClass(Class clz) {
try {
return ((Class) clz.getField("TYPE").get(null)).isPrimitive();
} catch (Exception e) {
return false;
}
}
/**
* 是否基础数据类型
*
* @param type
* @return
*/
private static boolean isBasicClass(Class type) {
return isWrapClass(type)
|| isCommonDataType(type)
|| BigDecimal.class.isAssignableFrom(type)
|| Date.class.isAssignableFrom(type)
|| String.class.isAssignableFrom(type);
}
/**
* 多次复制的对象
* PropertyUtils会缓存属性信息
*
* @param sourceList
* @param targetClass
* @param <T>
* @return
*/
public static <T, D> List<T> copyListProperties(List<D> sourceList, Class<T> targetClass) {
return copyListProperties(sourceList, targetClass, null);
}
/**
* 多次复制的对象
* PropertyUtils会缓存属性信息
*
* @param sourceList
* @param targetClass
* @param currentFunction
* @param <T>
* @return
*/
public static <T, D> List<T> copyListProperties(List<D> sourceList, Class<T> targetClass, CurrentFunction<Object, T> currentFunction) {
if (CollectionUtils.isEmpty(sourceList)) {
return Lists.newArrayList();
}
List<T> valueList = Lists.newArrayListWithExpectedSize(sourceList.size());
for (Object source : sourceList) {
T value = copyProperties(source, targetClass, currentFunction);
if (value == null) {
continue;
}
valueList.add(value);
}
return valueList;
}
/**
* 多次复制的对象
* PropertyUtils会缓存属性信息
*
* @param source 原始数据
* @param targetClass 返回的对象类型
* @param ignoreProperties 忽略的属性
* @param <T>
* @return
*/
public static <T> T copyProperties(Object source, Class<T> targetClass, String... ignoreProperties) {
return copyProperties(source, targetClass, null, ignoreProperties);
}
/**
* 多次复制的对象
* 缓存属性信息,便于下次直接赋值
*
* @param source 原始数据
* @param targetClass 返回的对象类型
* @param currentFunction 自定义实现
* @param ignoreProperties 忽略的属性
* @param <T>
* @return
*/
public static <T> T copyProperties(Object source, Class<T> targetClass, CurrentFunction<Object, T> currentFunction, String... ignoreProperties) {
if (source == null) {
return null;
}
T targetObj = null;
try {
targetObj = (T) targetClass.getDeclaredConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
log.warn("创建对象 {} 失败", targetClass.getName(), e);
return null;
}
List<String> ignorePropertiesList = ignoreProperties == null || ignoreProperties.length <= 0 ? null : Lists.newArrayList(ignoreProperties);
PropertyDescriptor[] targetPropertyDesc = PropertyUtils.getPropertyDescriptors(targetObj);
Map<String, FieldCanCopy> fieldCanCopyMap = FIELD_COPY_CACHE.get(targetClass);
Field[] sourceFields = null, targetFields = null;
if (fieldCanCopyMap == null) {
sourceFields = source.getClass().getDeclaredFields();
targetFields = targetClass.getDeclaredFields();
synchronized (targetClass) {
fieldCanCopyMap = FIELD_COPY_CACHE.get(targetClass);
if (fieldCanCopyMap == null) {
fieldCanCopyMap = Maps.newConcurrentMap();
FIELD_COPY_CACHE.put(targetClass, fieldCanCopyMap);
}
}
}
Class targetPropertyType = null, sourcePropertyType = null;
try {
for (int i = 0; i < targetPropertyDesc.length; i++) {
if (ignorePropertiesList != null && ignorePropertiesList.contains(targetPropertyDesc[i].getName())) {
continue;
}
targetPropertyType = targetPropertyDesc[i].getPropertyType();
boolean isCacheFill = isCacheFill(source, targetObj, targetPropertyType, fieldCanCopyMap, targetPropertyDesc[i].getName());
if (isCacheFill) {
continue;
}
if (targetPropertyDesc[i].getName().equalsIgnoreCase(Class.class.getSimpleName())) {
fieldCanCopyMap.put(targetPropertyDesc[i].getName(), new FieldCanCopy(false));
continue;
}
if (PropertyUtils.getWriteMethod(targetPropertyDesc[i]) == null) {
fieldCanCopyMap.put(targetPropertyDesc[i].getName(), new FieldCanCopy(false));
continue;
}
sourcePropertyType = PropertyUtils.getPropertyType(source, targetPropertyDesc[i].getName());
Object value = null;
if (sourcePropertyType != null) {
value = PropertyUtils.getProperty(source, targetPropertyDesc[i].getName());
if (value == null) {
continue;
}
//如果根据名称能取到值
if (targetPropertyType.equals(sourcePropertyType)) {
boolean isCollection = targetPropertyType.getClass().isArray() || value instanceof Collection || value instanceof Map;
if (!isCollection) {
PropertyUtils.setProperty(targetObj, targetPropertyDesc[i].getName(), value);
fieldCanCopyMap.put(targetPropertyDesc[i].getName(), new FieldCanCopy(true, DIRECT_ASSIGNMENT));
} else {
if (ObjectUtils.isEmpty(value)) {
continue;
}
Field field = getFieldByName(targetFields, targetPropertyDesc[i].getName());
Type[] types = ((ParameterizedType) field.getGenericType()).getActualTypeArguments();
if (types == null || types.length > 2) {
fieldCanCopyMap.put(targetPropertyDesc[i].getName(), new FieldCanCopy(false));
continue;
}
if (targetPropertyType.getClass().isArray()) {
if (types.length != 1) {
fieldCanCopyMap.put(targetPropertyDesc[i].getName(), new FieldCanCopy(false));
continue;
}
Class genericType = getCommonDataType(types[0].getClass(), types[0].getTypeName());
if (getCommonDataType(((Object[]) value).getClass()).equals(genericType)) {
PropertyUtils.setProperty(targetObj, targetPropertyDesc[i].getName(), value);
fieldCanCopyMap.put(targetPropertyDesc[i].getName(), new FieldCanCopy(true, DIRECT_ASSIGNMENT));
} else {
fieldCanCopyMap.put(targetPropertyDesc[i].getName(), new FieldCanCopy(false));
log.info("属性名称相同,类型为数组,但数组里面的子元素不是基本类型或类型不同,不做处理 name: {} targetPropertyType: {} sourcePropertyType: {}", targetPropertyDesc[i].getName(), targetPropertyType, sourcePropertyType);
}
} else if (value instanceof Collection) {
if (types.length != 1) {
fieldCanCopyMap.put(targetPropertyDesc[i].getName(), new FieldCanCopy(false));
continue;
}
Class genericType = getCommonDataType(types[0].getClass(), types[0].getTypeName());
if (getCommonDataType(((Collection) value).iterator().next().getClass()).equals(genericType)) {
PropertyUtils.setProperty(targetObj, targetPropertyDesc[i].getName(), value);
fieldCanCopyMap.put(targetPropertyDesc[i].getName(), new FieldCanCopy(true, DIRECT_ASSIGNMENT));
} else {
fieldCanCopyMap.put(targetPropertyDesc[i].getName(), new FieldCanCopy(false));
log.info("属性名称相同,类型为集合,但集合里面的属性获取失败,不做处理 name: {} targetPropertyType: {} sourcePropertyType: {}", targetPropertyDesc[i].getName(), targetPropertyType, sourcePropertyType);
}
} else if (value instanceof Map) {
if (types.length != 2) {
fieldCanCopyMap.put(targetPropertyDesc[i].getName(), new FieldCanCopy(false));
continue;
}
Class genericKeyType = getCommonDataType(types[0].getClass(), types[0].getTypeName());
Class genericValueType = getCommonDataType(types[1].getClass(), types[1].getTypeName());
Map<?, ?> keyValueMap = (Map) value;
boolean isKeyValueTypeSameFlag = false;
for (Map.Entry<?, ?> entry : keyValueMap.entrySet()) {
isKeyValueTypeSameFlag = getCommonDataType(entry.getKey().getClass()).equals(genericKeyType) && getCommonDataType(entry.getValue().getClass()).equals(genericValueType);
break;
}
if (isKeyValueTypeSameFlag) {
PropertyUtils.setProperty(targetObj, targetPropertyDesc[i].getName(), value);
fieldCanCopyMap.put(targetPropertyDesc[i].getName(), new FieldCanCopy(true, DIRECT_ASSIGNMENT));
} else {
fieldCanCopyMap.put(targetPropertyDesc[i].getName(), new FieldCanCopy(false));
log.info("属性名称相同,类型为Map,但Map的Key和Value存在不同的类型,不做处理 name: {} targetPropertyType: {} sourcePropertyType: {}", targetPropertyDesc[i].getName(), targetPropertyType, sourcePropertyType);
}
}
}
} else if (isBasicClass(targetPropertyType) && isBasicClass(sourcePropertyType)) {
//如果类型不同,且类型都是基本类型,尝试转换
sameNameDiffType(value, targetObj, targetPropertyDesc[i].getName(), targetPropertyType);
fieldCanCopyMap.put(targetPropertyDesc[i].getName(), new FieldCanCopy(true, TRANSFORM_ASSIGNMENT));
} else {
fieldCanCopyMap.put(targetPropertyDesc[i].getName(), new FieldCanCopy(false));
log.info("属性名称相同,但属性类型不同,且不是可以转换的类型,不做处理 name: {} targetPropertyType: {} sourcePropertyType: {}", targetPropertyDesc[i].getName(), targetPropertyType, sourcePropertyType);
}
continue;
}
Field field = getFieldByName(sourceFields, targetPropertyDesc[i].getName());
if (field == null) {
fieldCanCopyMap.put(targetPropertyDesc[i].getName(), new FieldCanCopy(false));
continue;
}
value = PropertyUtils.getProperty(source, field.getName());
if (value == null) {
continue;
}
sourcePropertyType = field.getType();
if (isSimilarClass(sourcePropertyType.getName(), targetPropertyType.getName())) {
//如果是dto/vo/entity三者转换,递归调用赋值
PropertyUtils.setProperty(targetObj, targetPropertyDesc[i].getName(), copyProperties(value, targetPropertyType));
fieldCanCopyMap.put(targetPropertyDesc[i].getName(), new FieldCanCopy(true, field.getName(), DIRECT_ASSIGNMENT));
continue;
}
//判断两者是不是都是基本数据类型,如果一个不是,则不能进行赋值,否则转换赋值
boolean isNotBasicType = !isBasicClass(targetPropertyType) || !isBasicClass(sourcePropertyType);
if (isNotBasicType) {
fieldCanCopyMap.put(targetPropertyDesc[i].getName(), new FieldCanCopy(false));
continue;
}
sameNameDiffType(value, targetObj, targetPropertyDesc[i].getName(), targetPropertyType);
fieldCanCopyMap.put(targetPropertyDesc[i].getName(), new FieldCanCopy(true, field.getName(), TRANSFORM_ASSIGNMENT));
}
if (currentFunction != null) {
targetObj = currentFunction.apply(source, targetObj);
}
} catch (Exception e) {
log.warn("复制属性错误 source:{} class: {}", JSONObject.toJSONString(source), targetClass, e);
}
return targetObj;
}
private static <T> void sameNameDiffType(Object value, T targetObj, String propertyName, Class targetPropertyType) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
String valueStr = null;
if (value instanceof Date) {
valueStr = DatetimeUtil.formatDate((Date) value, DatetimeUtil.YYYY_MM_DD_HH_MM_SS_L_C);
} else if (value instanceof BigDecimal) {
valueStr = ((BigDecimal) value).toPlainString();
} else {
valueStr = String.valueOf(value);
}
PropertyUtils.setProperty(targetObj, propertyName, getCommonDataTypeValue(targetPropertyType, valueStr));
}
/**
* 是否是项目中存在的 dto/vo/entity 三者之间的转换
*
* @param sourceClass
* @param targetClass
* @return
*/
private static boolean isSimilarClass(String sourceClass, String targetClass) {
String[] sourceClassSplits = getClassStr(sourceClass);
String[] targetClassSplits = getClassStr(targetClass);
if (sourceClassSplits == null || targetClassSplits == null) {
return false;
}
return sourceClassSplits[sourceClassSplits.length - 1].equalsIgnoreCase(targetClassSplits[targetClassSplits.length - 1]);
}
/**
* 根据属性名判断是否相同
*
* @param fields
* @param className
* @return
*/
private static Field getFieldByName(Field[] fields, String className) {
String[] typeNames = getClassStr(className);
if (typeNames == null) {
return null;
}
String typeName = typeNames[typeNames.length - 1];
String fieldName = null;
boolean isSame = false;
for (Field field : fields) {
fieldName = field.getName();
if ("serialVersionUID".equalsIgnoreCase(fieldName)) {
continue;
}
isSame = fieldName.equalsIgnoreCase(typeName) || fieldName.equalsIgnoreCase(typeName + "vo") || fieldName.equalsIgnoreCase(typeName + "dto");
if (isSame) {
return field;
}
}
return null;
}
/**
* 自定义vo,dto为同一个对象信息
*
* @param className
* @return
*/
private static String[] getClassStr(String className) {
if (StringUtils.isEmpty(className)) {
return null;
}
String[] sourceClassSplits = className.split("\\.", -1);
String sourceName = sourceClassSplits[sourceClassSplits.length - 1];
if (sourceName.toLowerCase().endsWith("dto")) {
sourceName = sourceName.substring(0, sourceName.length() - 3);
} else if (sourceName.toLowerCase().endsWith("vo")) {
sourceName = sourceName.substring(0, sourceName.length() - 2);
}
sourceClassSplits[sourceClassSplits.length - 1] = sourceName;
return sourceClassSplits;
}
/**
* 是否缓存直接填充值,如果是,则直接填充值,否则分析是否填充值
*
* @param source
* @param targetObj
* @param targetPropertyType
* @param fieldCanCopyMap
* @param targetPropertyDescName
* @param <T>
* @return
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws NoSuchMethodException
*/
private static <T> boolean isCacheFill(Object source, T targetObj, Class targetPropertyType, Map<String, FieldCanCopy> fieldCanCopyMap, String targetPropertyDescName) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
FieldCanCopy fieldCanCopy = fieldCanCopyMap.get(targetPropertyDescName);
if (fieldCanCopy == null) {
return false;
}
Object value = null;
if (fieldCanCopy != null && fieldCanCopy.isCanCopy()) {
if (StringUtils.isNotEmpty(fieldCanCopy.getFieldName())) {
value = PropertyUtils.getProperty(source, fieldCanCopy.getFieldName());
} else {
value = PropertyUtils.getProperty(source, targetPropertyDescName);
}
if (value == null) {
return true;
}
switch (fieldCanCopy.getFillValue()) {
case DIRECT_ASSIGNMENT:
PropertyUtils.setProperty(targetObj, targetPropertyDescName, value);
break;
case TRANSFORM_ASSIGNMENT:
sameNameDiffType(value, targetObj, targetPropertyDescName, targetPropertyType);
break;
default:
break;
}
}
return true;
}
/**
* 是否能复制
*/
@Data
static class FieldCanCopy {
/**
* 默认不能复制
*/
private boolean canCopy = false;
/**
* 复制属性名称
*/
private String fieldName;
/**
* 填充值方式
* 1、PropertyUtils.setProperty(targetObj, targetPropertyDesc[i].getName(), value);
* 2、sameNameDiffType(value, targetObj, targetPropertyDesc[i].getName(), targetPropertyType);
*/
private int fillValue;
public FieldCanCopy(boolean canCopy) {
this.canCopy = canCopy;
}
public FieldCanCopy(boolean canCopy, int fillValue) {
this.canCopy = canCopy;
this.fillValue = fillValue;
}
public FieldCanCopy(boolean canCopy, String fieldName, int fillValue) {
this.canCopy = canCopy;
this.fieldName = fieldName;
this.fillValue = fillValue;
}
}
}
注意:数组,Map,List,Set(List和Set可以是对象,数组和Map只是基本类型)
使用缓存,第一次复制耗时340ms,第二次0ms,查询List转换时可以提高性能