com.diboot.core.util.BeanUtils Maven / Gradle / Ivy
/*
* Copyright (c) 2015-2020, www.dibo.ltd ([email protected]).
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.diboot.core.util;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.toolkit.LambdaUtils;
import com.baomidou.mybatisplus.core.toolkit.support.LambdaMeta;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.diboot.core.config.Cons;
import com.diboot.core.converter.*;
import com.diboot.core.data.copy.AcceptAnnoCopier;
import com.diboot.core.entity.BaseEntity;
import com.diboot.core.exception.BusinessException;
import com.diboot.core.vo.LabelValue;
import com.diboot.core.vo.Status;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.ibatis.reflection.property.PropertyNamer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.core.ResolvableType;
import org.springframework.core.convert.ConversionService;
import org.springframework.util.ReflectionUtils;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* Bean相关处理工具类
* @author [email protected]
* @version v2.0
* @date 2019/01/01
*/
@SuppressWarnings({"unchecked", "rawtypes", "JavaDoc", "unused"})
public class BeanUtils {
private static final Logger log = LoggerFactory.getLogger(BeanUtils.class);
/**
* 连接符号
*/
private static final String CHANGE_FLAG = "->";
/**
* 忽略对比的字段
*/
private static final Set IGNORE_FIELDS = new HashSet(){{
add(Cons.FieldName.createTime.name());
}};
/**
* Copy属性到另一个对象
* @param source
* @param target
*/
@SuppressWarnings("UnusedReturnValue")
public static Object copyProperties(Object source, Object target){
// 链式调用无法使用BeanCopier拷贝,换用BeanUtils
org.springframework.beans.BeanUtils.copyProperties(source, target);
// 处理Accept注解标识的不同字段名拷贝
AcceptAnnoCopier.copyAcceptProperties(source, target);
return target;
}
/***
* 将对象转换为另外的对象实例
* @param source
* @param clazz
* @param
* @return
*/
public static T convert(Object source, Class clazz){
if(source == null){
return null;
}
T target = null;
try{
target = clazz.getConstructor().newInstance();
copyProperties(source, target);
}
catch (Exception e){
log.warn("对象转换异常, class={}", clazz.getName());
}
return target;
}
/***
* 将对象转换为另外的对象实例
* @param sourceList
* @param clazz
* @param
* @return
*/
@SuppressWarnings("unchecked")
public static List convertList(List> sourceList, Class clazz) {
if(V.isEmpty(sourceList)){
return Collections.emptyList();
}
// 类型相同,直接跳过
if (clazz.equals(sourceList.get(0).getClass())) {
return (List) sourceList;
}
// 不同,则转换
List resultList = new ArrayList<>(sourceList.size());
try{
for(Object source : sourceList){
T target = clazz.getConstructor().newInstance();
copyProperties(source, target);
resultList.add(target);
}
}
catch (Exception e){
log.error("对象转换异常, class: {}, error: {}", clazz.getName(), e.getMessage());
return Collections.emptyList();
}
return resultList;
}
/***
* 附加Map中的属性值到Model
* @param model
* @param propMap
*/
public static void bindProperties(Object model, Map propMap){
if (V.isAnyEmpty(model, propMap)) {
return;
}
BeanWrapper beanWrapper = getBeanWrapper(model);
for(Map.Entry entry : propMap.entrySet()){
try{
beanWrapper.setPropertyValue(entry.getKey(), entry.getValue());
}
catch (Exception e){
log.debug("复制属性{}.{}异常: {}", model.getClass().getSimpleName(), entry.getKey(), e.getMessage());
}
}
}
/***
* 获取对象的属性值
* @param obj
* @param field
* @return
*/
public static Object getProperty(Object obj, String field){
if(field == null) {
return null;
}
if(obj instanceof Map){
Map objMap = (Map)obj;
return objMap.get(field);
}
try {
BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(obj);
return wrapper.getPropertyValue(field);
}
catch (Exception e) {
log.warn("获取对象属性值出错,返回null", e);
}
return null;
}
/***
* 获取对象的属性值并转换为String
* @param obj
* @param field
* @return
*/
public static String getStringProperty(Object obj, String field){
Object property = getProperty(obj, field);
if(property == null){
return null;
}
return String.valueOf(property);
}
/***
* 设置属性值
* @param obj
*/
public static BeanWrapper getBeanWrapper(Object obj) {
BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(obj);
if(wrapper.getConversionService() == null){
ConversionService conversionService = ContextHelper.getBean(EnhancedConversionService.class);
wrapper.setConversionService(conversionService);
}
return wrapper;
}
/***
* 设置属性值
* @param obj
* @param field
* @param value
*/
public static void setProperty(Object obj, String field, Object value) {
BeanWrapper wrapper = getBeanWrapper(obj);
wrapper.setPropertyValue(field, value);
}
/**
* 类型class对象-转换方法
*/
private static final Map, Function> fieldConverterMap = new HashMap, Function>() {{
put(Integer.class, Integer::parseInt);
put(Long.class, Long::parseLong);
put(Double.class, Double::parseDouble);
put(BigDecimal.class, BigDecimal::new);
put(Float.class, Float::parseFloat);
put(Boolean.class, V::isTrue);
put(Date.class, D::fuzzyConvert);
}};
/**
* 转换为field对应的类型
* @param value
* @param field
* @return
*/
public static Object convertValueToFieldType(Object value, Field field){
if(value == null){
return null;
}
return convertValueToFieldType(value, field.getType());
}
/**
* 转换为field对应的类型
* @param value
* @param fieldType
* @return
*/
public static Object convertValueToFieldType(Object value, Class> fieldType){
if(value == null){
return null;
}
if (value.getClass().equals(fieldType)) {
return value;
}
String valueStr = S.valueOf(value);
if (fieldConverterMap.containsKey(fieldType)) {
return fieldConverterMap.get(fieldType).apply(valueStr);
} else if (LocalDate.class.equals(fieldType) || LocalDateTime.class.equals(fieldType)) {
Date dateVal = (value instanceof Date) ? (Date) value : D.fuzzyConvert(valueStr);
if (dateVal == null) {
return null;
}
ZonedDateTime zonedDateTime = dateVal.toInstant().atZone(ZoneId.systemDefault());
return LocalDateTime.class.equals(fieldType) ? zonedDateTime.toLocalDateTime() : zonedDateTime.toLocalDate();
} else if (Serializable.class.isAssignableFrom(fieldType)) {
return JSON.parseObject(valueStr, fieldType);
}
return value;
}
/***
* Key-Object对象Map
* @param allLists
* @param getterFns
* @return
*/
public static Map convertToStringKeyObjectMap(List allLists, IGetter... getterFns){
String[] fields = convertGettersToFields(getterFns);
return convertToStringKeyObjectMap(allLists, fields);
}
/***
* Key-Object对象Map
* @param allLists
* @param fields
* @return
*/
public static Map convertToStringKeyObjectMap(List allLists, String... fields){
if(allLists == null || allLists.isEmpty()){
return Collections.EMPTY_MAP;
}
Map allListMap = new LinkedHashMap<>(allLists.size());
ModelKeyGenerator keyGenerator = new ModelKeyGenerator(fields);
// 转换为map
try {
for (T model : allLists) {
String key = keyGenerator.generate(model);
if (key != null) {
allListMap.put(key, model);
}
else{
log.warn("{} 的属性 {} 值存在 null,转换结果需要确认!", model.getClass().getName(), fields[0]);
}
}
}
catch(Exception e){
log.warn("转换key-model异常", e);
}
return allListMap;
}
/***
* Key-Object对象Map
* @param allLists
* @param getterFns
* @return
*/
public static Map> convertToStringKeyObjectListMap(List allLists, IGetter... getterFns){
String[] fields = convertGettersToFields(getterFns);
return convertToStringKeyObjectListMap(allLists, fields);
}
/***
* Key-Object-List列表Map
* @param allLists
* @param fields
* @param
* @return
*/
public static Map> convertToStringKeyObjectListMap(List allLists, String... fields){
if (V.isEmpty(allLists)) {
return Collections.emptyMap();
}
Map> allListMap = new LinkedHashMap<>(allLists.size());
ModelKeyGenerator keyGenerator = new ModelKeyGenerator(fields);
// 转换为map
try {
for (T model : allLists) {
String key = keyGenerator.generate(model);
if(key != null){
List list = allListMap.computeIfAbsent(key, k -> new ArrayList<>());
list.add(model);
}
else{
log.warn("{} 的属性 {} 值存在 null,转换结果需要确认!", model.getClass().getName(), fields[0]);
}
}
} catch (Exception e){
log.warn("转换key-model-list异常", e);
}
return allListMap;
}
/**
* key生成器,按照传入的fields字段列表给指定对象生成key
*/
private static class ModelKeyGenerator {
private final String[] fields;
/**
* fields是否为空
*/
private final boolean isFieldsEmpty;
/**
* fields是否只有一个元素
*/
private final boolean isFieldsOnlyOne;
public ModelKeyGenerator(String[] fields) {
this.fields = fields;
isFieldsEmpty = V.isEmpty(fields);
isFieldsOnlyOne = !isFieldsEmpty && fields.length == 1;
}
/**
* 从model中提取指定字段生成key,如果为指定字段则默认为id字段
* 不建议大量数据循环时调用
*
* @param model 提取对象
* @return model中字段生成的key
*/
public String generate(Object model) {
String key = null;
if (isFieldsEmpty) {
//未指定字段,以id为key
return getStringProperty(model, Cons.FieldName.id.name());
}
// 指定了一个字段,以该字段为key,类型同该字段
else if (isFieldsOnlyOne) {
return getStringProperty(model, fields[0]);
} else {
// 指定了多个字段,以字段S.join的结果为key,类型为String
List