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
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
# 5.8.38(2025-04-26)
|
||||
# 5.8.38(2025-05-07)
|
||||
|
||||
### 🐣新特性
|
||||
* 【core 】 `PathUtil#del`增加null检查(pr#1331@Gitee)
|
||||
@ -14,6 +14,7 @@
|
||||
* 【extra 】 `TemplateConfig`增加`setUseCache`方法(issue#IC3JRY@Gitee)
|
||||
* 【extra 】 `AbstractFtp`增加`rename`方法(issue#IC3PMI@Gitee)
|
||||
* 【core 】 优化`PropDesc`缓存注解判断,提升性能(pr#1335@Gitee)
|
||||
* 【core 】 添加`RecordUtil`支持record类(issue#3931@Github)
|
||||
|
||||
### 🐞Bug修复
|
||||
* 【setting】 修复`Setting`autoLoad可能的加载为空的问题(issue#3919@Github)
|
||||
|
@ -12,6 +12,7 @@ import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -48,7 +49,11 @@ public class BeanDesc implements Serializable {
|
||||
public BeanDesc(Class<?> beanClass) {
|
||||
Assert.notNull(beanClass);
|
||||
this.beanClass = beanClass;
|
||||
init();
|
||||
if(RecordUtil.isRecord(beanClass)){
|
||||
initForRecord();
|
||||
}else{
|
||||
init();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -153,6 +158,27 @@ public class BeanDesc implements Serializable {
|
||||
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>
|
||||
* 查找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