common-module/utils/BeanUtils.java
cuijiawang ea58e018b4 init
2025-05-27 17:58:49 +08:00

514 lines
16 KiB
Java
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.sgcc.utils;
import com.google.common.collect.Maps;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
/**
* 实体转化工具类
*
* @author zhaoyuanyuan
* @version 1.0.0
* @date 2024/06/24 17:35
*/
@Slf4j
public class BeanUtils {
private static final String CLASS = "class";
private BeanUtils() {
throw new IllegalStateException("Utility class");
}
/**
* 判断对象是否为数字
*
* @param o
* @return
*/
public static boolean isNumber(Object o) {
if (o == null) {
return false;
}
if (o instanceof Number) {
return true;
}
if (o instanceof String) {
try {
Double.parseDouble((String) o);
return true;
} catch (NumberFormatException e) {
return false;
}
}
return false;
}
/**
* 将bean转化为map
*
* @param clazz bean
* @param <T> 泛型
* @return Map<String, Object> 返回对象
*/
public static <T> Map<String, Object> toMap(final T clazz) {
Map<String, Object> paramsMap = Maps.newHashMap();
try {
BeanInfo bi = Introspector.getBeanInfo(clazz.getClass());
PropertyDescriptor[] pd = bi.getPropertyDescriptors();
for (int i = 0; i < pd.length; i++) {
String name = pd[i].getName();
Method method = pd[i].getReadMethod();
Object value = method.invoke(clazz);
if (!CLASS.equals(name)) {
paramsMap.put(name, value);
}
}
} catch (IntrospectionException ie) {
log.error("IntrospectionException.className=" + clazz.getClass() + "BeanInfo error : ", ie);
} catch (Exception e) {
log.error("Exception.className=" + clazz.getClass() + "Method error :", e);
}
return paramsMap;
}
/**
* 获取到对象中属性为指定值的属性名
*
* @param source 要拷贝的对象
* @param values 指定的值数组
* @return
*/
public static String[] getPropertyNamesWithValues(Object source, String... values) {
List<String> valueList = (values != null ? Arrays.asList(values) : null);
final BeanWrapper src = new BeanWrapperImpl(source);
PropertyDescriptor[] pds = src.getPropertyDescriptors();
Set<String> propertyNames = new HashSet<>();
for (PropertyDescriptor pd : pds) {
Object srcValue = src.getPropertyValue(pd.getName());
if (valueList == null && srcValue == null) {
propertyNames.add(pd.getName());
} else if (valueList != null && valueList.contains(srcValue)) {
propertyNames.add(pd.getName());
} else {
// DO NOTHING
}
}
String[] result = new String[propertyNames.size()];
return propertyNames.toArray(result);
}
/**
* 列表实体类属性拷贝忽略null值
*
* @param fromList 待转换实体列数组
* @param tClass 目标类
* @param <F>
* @param <T>
* @return
*/
public static <F, T> List<T> copyPropertiesIgnoreNull(List<F> fromList, Class<T> tClass) {
return copyPropertiesIgnoreValues(fromList, tClass, (String[]) null);
}
/**
* 实体类属性拷贝忽略null值、空字符串""和"null"
*
* @param fromList 待转换实体列数组
* @param tClass 目标类
* @param <F>
* @param <T>
* @return
*/
public static <F, T> List<T> copyPropertiesIgnoreEmpty(List<F> fromList, Class<T> tClass) {
return copyPropertiesIgnoreValues(fromList, tClass, null, "", "null");
}
/**
* 实体类列表属性拷贝,忽略指定值
* 将entityList转换成modelList
*
* @param fromList 待转换实体列数组
* @param tClass 目标类
* @param values 指定的值数组
* @param <F>
* @param <T>
* @return
*/
public static <F, T> List<T> copyPropertiesIgnoreValues(List<F> fromList, Class<T> tClass, String... values) {
Assert.notNull(tClass, "tClass must not be null.");
List<T> tList = new ArrayList<>();
if (fromList != null && !fromList.isEmpty()) {
for (F f : fromList) {
T t = copyPropertiesIgnoreValues(f, tClass, values);
tList.add(t);
}
}
return tList;
}
/**
* 实体类列表属性拷贝
* 将entityList转换成modelList
*
* @param fromList 待转换实体列数组
* @param tClass 目标类
* @param <F>
* @param <T>
* @return
*/
public static <F, T> List<T> copyProperties(List<F> fromList, Class<T> tClass) {
Assert.notNull(tClass, "tClass must not be null.");
List<T> tList = new ArrayList<>();
if (fromList != null && !fromList.isEmpty()) {
for (F f : fromList) {
T t = copyProperties(f, tClass);
tList.add(t);
}
}
return tList;
}
/**
* 实体类属性拷贝忽略null值
*
* @param entity 实体类
* @param modelClass 目标类
* @param <F>
* @param <T>
* @return
*/
public static <F, T> T copyPropertiesIgnoreNull(F entity, Class<T> modelClass) {
return copyPropertiesIgnoreValues(entity, modelClass, (String[]) null);
}
/**
* 实体类属性拷贝忽略null值、空字符串""和"null"
*
* @param entity 实体类
* @param modelClass 目标类
* @param <F>
* @param <T>
* @return
*/
public static <F, T> T copyPropertiesIgnoreEmpty(F entity, Class<T> modelClass) {
return copyPropertiesIgnoreValues(entity, modelClass, null, "", "null");
}
/**
* 实体类属性拷贝,忽略指定值
*
* @param entity 实体类
* @param modelClass 目标类
* @param values 指定的值数组
* @param <F>
* @param <T>
* @return
*/
public static <F, T> T copyPropertiesIgnoreValues(F entity, Class<T> modelClass, String... values) {
return copyProperties(entity, modelClass, getPropertyNamesWithValues(entity, values));
}
/**
* 实体类属性拷贝
*
* @param entity 实体类
* @param modelClass 目标类
* @param <F>
* @param <T>
* @return
*/
public static <F, T> T copyProperties(F entity, Class<T> modelClass) {
return copyProperties(entity, modelClass, (String[]) null);
}
/**
* 实体类属性拷贝
*
* @param entity 实体类
* @param modelClass 目标类
* @param ignoreProperties 忽略属性列表
* @param <F>
* @param <T>
* @return
*/
public static <F, T> T copyProperties(F entity, Class<T> modelClass, String... ignoreProperties) {
Assert.notNull(modelClass, "modelClass must not be null.");
Object model = null;
try {
model = modelClass.newInstance();
} catch (InstantiationException e) {
log.error("copyProperties: InstantiationException", e);
} catch (IllegalAccessException e) {
log.error("copyProperties: IllegalAccessException", e);
}
if (entity != null) {
org.springframework.beans.BeanUtils.copyProperties(entity, model, ignoreProperties);
} else {
// DO NOTHING
}
return (T) model;
}
/**
* 将下划线大写方式命名的字符串转换为驼峰式。
* 如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。</br>
* 例如hello_world->helloWorld
*
* @param name 转换前的下划线大写方式命名的字符串
* @return 转换后的驼峰式命名的字符串
*/
public static String camelName(String name) {
StringBuilder result = new StringBuilder();
// 快速检查
if (name == null || name.isEmpty()) {
// 没必要转换
return "";
} else if (!name.contains("_")) {
// 不含下划线,仅将首字母小写
return name.substring(0, 1).toLowerCase() + name.substring(1).toLowerCase();
}
// 用下划线将原始字符串分割
String[] camels = name.split("_");
for (String camel : camels) {
// 跳过原始字符串中开头、结尾的下换线或双重下划线
if (camel.isEmpty()) {
continue;
}
// 处理真正的驼峰片段
if (result.length() == 0) {
// 第一个驼峰片段,全部字母都小写
result.append(camel.toLowerCase());
} else {
// 其他的驼峰片段,首字母大写
result.append(camel.substring(0, 1).toUpperCase());
result.append(camel.substring(1).toLowerCase());
}
}
return result.toString();
}
/**
* 将下划线大写方式命名的字符串转换为驼峰式。
* 如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。</br>
* 例如hello_world,test_id->helloWorld,testId
*
* @param names 转换前的下划线大写方式命名的字符串
* @return 转换后的驼峰式命名的字符串
*/
public static String camelNames(String names) {
if (names == null || names.equals("")) {
return null;
}
StringBuilder sb = new StringBuilder();
String[] fs = names.split(",");
for (String field : fs) {
field = camelName(field);
sb.append(field + ",");
}
String result = sb.toString();
return result.substring(0, result.length() - 1);
}
/**
* 将下划线大写方式命名的字符串转换为驼峰式。
* (首字母写) 如果转换前的下划线大写方式命名的字符串为空,
* 则返回空字符串。</br>
* 例如hello_world->HelloWorld
*
* @param name 转换前的下划线大写方式命名的字符串
* @return 转换后的驼峰式命名的字符串
*/
public static String camelNameCapFirst(String name) {
// 转换为首字母小写的驼峰片段
String camel = camelName(name);
if (camel == null || camel.length() < 1) {
return name;
}
// 首字母大写
char[] charArray = camel.toCharArray();
charArray[0] -= 32;
return String.valueOf(charArray);
}
/**
* 将驼峰命名转化成下划线
*
* @param param
* @return
*/
public static String camelToUnderline(String param) {
if (param == null) {
return null;
}
int paramLen = param.length();
if (paramLen < 3) {
return param.toLowerCase();
}
int wordCount = 0;
StringBuilder sb = new StringBuilder(param);
// 从第三个字符开始 避免命名不规范
for (int i = 2; i < paramLen; i++) {
if (Character.isUpperCase(param.charAt(i))) {
sb.insert(i + wordCount, "_");
wordCount += 1;
}
}
return sb.toString().toLowerCase();
}
/**
* 根据指定的类名判定指定的类是否存在。
*
* @param className
* @return
*/
public static boolean validClass(String className) {
try {
Class.forName(className);
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
/**
* 判定类是否继承自父类
*
* @param cls 子类
* @param parentClass 父类
* @return
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public static boolean isInherit(Class cls, Class parentClass) {
return parentClass.isAssignableFrom(cls);
}
/**
* 输入基类包名,扫描其下的类,返回类的全路径
*
* @param basePackages 如com.hotent
* @return
* @throws IllegalArgumentException
*/
@SuppressWarnings("all")
public static List<String> scanPackages(String basePackages)
throws IllegalArgumentException {
ResourcePatternResolver rl = new PathMatchingResourcePatternResolver();
MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(
rl);
List result = new ArrayList();
String[] arrayPackages = basePackages.split(",");
try {
for (int j = 0; j < arrayPackages.length; j++) {
String packageToScan = arrayPackages[j];
String packagePart = packageToScan.replace('.', '/');
String classPattern = "classpath*:/" + packagePart
+ "/**/*.class";
Resource[] resources = rl.getResources(classPattern);
for (int i = 0; i < resources.length; i++) {
Resource resource = resources[i];
MetadataReader metadataReader = metadataReaderFactory
.getMetadataReader(resource);
String className = metadataReader.getClassMetadata()
.getClassName();
result.add(className);
}
}
} catch (Exception e) {
new IllegalArgumentException("scan pakcage class error,pakcages:"
+ basePackages);
}
return result;
}
/**
* 将字符串数据按照指定的类型进行转换。
*
* @param typeName 实际的数据类型
* @param value 字符串值。
* @return Object
*/
public static Object convertByActType(String typeName, String value) {
Object o = null;
if (typeName.equals("int")) {
o = Integer.parseInt(value);
} else if (typeName.equals("short")) {
o = Short.parseShort(value);
} else if (typeName.equals("long")) {
o = Long.parseLong(value);
} else if (typeName.equals("float")) {
o = Float.parseFloat(value);
} else if (typeName.equals("double")) {
o = Double.parseDouble(value);
} else if (typeName.equals("boolean")) {
o = Boolean.parseBoolean(value);
} else if (typeName.equals("java.lang.String")) {
o = value;
} else {
o = value;
}
return o;
}
/**
* 根据类和成员变量名称获取成员变量。
*
* @param thisClass
* @param fieldName
* @return
* @throws NoSuchFieldException Field
*/
public static Field getField(Class<?> thisClass, String fieldName)
throws NoSuchFieldException {
if (fieldName == null) {
throw new NoSuchFieldException("Error field !");
}
Field field = thisClass.getDeclaredField(fieldName);
return field;
}
/**
* 数据列表去重
*
* @param list
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public static void removeDuplicate(List list) {
HashSet h = new HashSet(list);
list.clear();
list.addAll(h);
}
private static void handleReflectionException(Exception e) {
ReflectionUtils.handleReflectionException(e);
}
}