mirror of
https://gitee.com/dromara/hutool.git
synced 2025-06-28 13:34:09 +08:00
添加RecordUtil
支持record类(issue#3931@Github)
This commit is contained in:
parent
87a6bdeaaa
commit
b8e6b1ecc0
@ -2,7 +2,7 @@
|
|||||||
# 🚀Changelog
|
# 🚀Changelog
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------
|
||||||
# 5.8.38(2025-04-26)
|
# 5.8.38(2025-05-07)
|
||||||
|
|
||||||
### 🐣新特性
|
### 🐣新特性
|
||||||
* 【core 】 `PathUtil#del`增加null检查(pr#1331@Gitee)
|
* 【core 】 `PathUtil#del`增加null检查(pr#1331@Gitee)
|
||||||
@ -14,6 +14,7 @@
|
|||||||
* 【extra 】 `TemplateConfig`增加`setUseCache`方法(issue#IC3JRY@Gitee)
|
* 【extra 】 `TemplateConfig`增加`setUseCache`方法(issue#IC3JRY@Gitee)
|
||||||
* 【extra 】 `AbstractFtp`增加`rename`方法(issue#IC3PMI@Gitee)
|
* 【extra 】 `AbstractFtp`增加`rename`方法(issue#IC3PMI@Gitee)
|
||||||
* 【core 】 优化`PropDesc`缓存注解判断,提升性能(pr#1335@Gitee)
|
* 【core 】 优化`PropDesc`缓存注解判断,提升性能(pr#1335@Gitee)
|
||||||
|
* 【core 】 添加`RecordUtil`支持record类(issue#3931@Github)
|
||||||
|
|
||||||
### 🐞Bug修复
|
### 🐞Bug修复
|
||||||
* 【setting】 修复`Setting`autoLoad可能的加载为空的问题(issue#3919@Github)
|
* 【setting】 修复`Setting`autoLoad可能的加载为空的问题(issue#3919@Github)
|
||||||
|
@ -12,6 +12,7 @@ import java.lang.reflect.Field;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -48,7 +49,11 @@ public class BeanDesc implements Serializable {
|
|||||||
public BeanDesc(Class<?> beanClass) {
|
public BeanDesc(Class<?> beanClass) {
|
||||||
Assert.notNull(beanClass);
|
Assert.notNull(beanClass);
|
||||||
this.beanClass = beanClass;
|
this.beanClass = beanClass;
|
||||||
init();
|
if(RecordUtil.isRecord(beanClass)){
|
||||||
|
initForRecord();
|
||||||
|
}else{
|
||||||
|
init();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -153,6 +158,27 @@ public class BeanDesc implements Serializable {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 针对Record类的反射初始化
|
||||||
|
*/
|
||||||
|
private void initForRecord() {
|
||||||
|
final Class<?> beanClass = this.beanClass;
|
||||||
|
final Map<String, PropDesc> propMap = this.propMap;
|
||||||
|
|
||||||
|
final List<Method> getters = ReflectUtil.getPublicMethods(beanClass, method -> 0 == method.getParameterCount());
|
||||||
|
// 排除静态属性和对象子类
|
||||||
|
final Field[] fields = ReflectUtil.getFields(beanClass, field -> !ModifierUtil.isStatic(field) && !ReflectUtil.isOuterClassField(field));
|
||||||
|
for (final Field field : fields) {
|
||||||
|
for (final Method getter : getters) {
|
||||||
|
if (field.getName().equals(getter.getName())) {
|
||||||
|
//record对象,getter方法与字段同名
|
||||||
|
final PropDesc prop = new PropDesc(field, getter, null);
|
||||||
|
propMap.putIfAbsent(prop.getFieldName(), prop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据字段创建属性描述<br>
|
* 根据字段创建属性描述<br>
|
||||||
* 查找Getter和Setter方法时会:
|
* 查找Getter和Setter方法时会:
|
||||||
|
110
hutool-core/src/main/java/cn/hutool/core/bean/RecordUtil.java
Normal file
110
hutool-core/src/main/java/cn/hutool/core/bean/RecordUtil.java
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
package cn.hutool.core.bean;
|
||||||
|
|
||||||
|
import cn.hutool.core.bean.copier.ValueProvider;
|
||||||
|
import cn.hutool.core.util.ClassUtil;
|
||||||
|
import cn.hutool.core.util.JdkUtil;
|
||||||
|
import cn.hutool.core.util.ReflectUtil;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.AbstractMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* java.lang.Record 相关工具类封装<br>
|
||||||
|
* 来自于FastJSON2的BeanUtils
|
||||||
|
*
|
||||||
|
* @author fastjson2, Looly
|
||||||
|
* @since 5.8.38
|
||||||
|
*/
|
||||||
|
public class RecordUtil {
|
||||||
|
|
||||||
|
private static volatile Class<?> RECORD_CLASS;
|
||||||
|
|
||||||
|
private static volatile Method METHOD_GET_RECORD_COMPONENTS;
|
||||||
|
private static volatile Method METHOD_COMPONENT_GET_NAME;
|
||||||
|
private static volatile Method METHOD_COMPONENT_GET_GENERIC_TYPE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断给定类是否为Record类
|
||||||
|
*
|
||||||
|
* @param clazz 类
|
||||||
|
* @return 是否为Record类
|
||||||
|
*/
|
||||||
|
public static boolean isRecord(final Class<?> clazz) {
|
||||||
|
if (JdkUtil.JVM_VERSION < 14) {
|
||||||
|
// JDK14+支持Record类
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final Class<?> superClass = clazz.getSuperclass();
|
||||||
|
if (superClass == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RECORD_CLASS == null) {
|
||||||
|
// 此处不使用同步代码,重复赋值并不影响判断
|
||||||
|
final String superclassName = superClass.getName();
|
||||||
|
if ("java.lang.Record".equals(superclassName)) {
|
||||||
|
RECORD_CLASS = superClass;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return superClass == RECORD_CLASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Record类中所有字段名称,getter方法名与字段同名
|
||||||
|
*
|
||||||
|
* @param recordClass Record类
|
||||||
|
* @return 字段数组
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static Map.Entry<String, Type>[] getRecordComponents(final Class<?> recordClass) {
|
||||||
|
if (JdkUtil.JVM_VERSION < 14) {
|
||||||
|
// JDK14+支持Record类
|
||||||
|
return new Map.Entry[0];
|
||||||
|
}
|
||||||
|
if (null == METHOD_GET_RECORD_COMPONENTS) {
|
||||||
|
METHOD_GET_RECORD_COMPONENTS = ReflectUtil.getMethod(Class.class, "getRecordComponents");
|
||||||
|
}
|
||||||
|
|
||||||
|
final Class<Object> recordComponentClass = ClassUtil.loadClass("java.lang.reflect.RecordComponent");
|
||||||
|
if (METHOD_COMPONENT_GET_NAME == null) {
|
||||||
|
METHOD_COMPONENT_GET_NAME = ReflectUtil.getMethod(recordComponentClass, "getName");
|
||||||
|
}
|
||||||
|
if (METHOD_COMPONENT_GET_GENERIC_TYPE == null) {
|
||||||
|
METHOD_COMPONENT_GET_GENERIC_TYPE = ReflectUtil.getMethod(recordComponentClass, "getGenericType");
|
||||||
|
}
|
||||||
|
|
||||||
|
final Object[] components = ReflectUtil.invoke(recordClass, METHOD_GET_RECORD_COMPONENTS);
|
||||||
|
final Map.Entry<String, Type>[] entries = new Map.Entry[components.length];
|
||||||
|
for (int i = 0; i < components.length; i++) {
|
||||||
|
entries[i] = new AbstractMap.SimpleEntry<>(
|
||||||
|
ReflectUtil.invoke(components[i], METHOD_COMPONENT_GET_NAME),
|
||||||
|
ReflectUtil.invoke(components[i], METHOD_COMPONENT_GET_GENERIC_TYPE)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实例化Record类
|
||||||
|
*
|
||||||
|
* @param recordClass 类
|
||||||
|
* @param valueProvider 参数值提供器
|
||||||
|
* @return Record类
|
||||||
|
*/
|
||||||
|
public static Object newInstance(final Class<?> recordClass, final ValueProvider<String> valueProvider) {
|
||||||
|
final Map.Entry<String, Type>[] recordComponents = getRecordComponents(recordClass);
|
||||||
|
final Object[] args = new Object[recordComponents.length];
|
||||||
|
for (int i = 0; i < args.length; i++) {
|
||||||
|
args[i] = valueProvider.value(recordComponents[i].getKey(), recordComponents[i].getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ReflectUtil.newInstance(recordClass, args);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user