mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
add FieldReflect
This commit is contained in:
parent
7ae93644e3
commit
8e4b24f8fa
@ -30,7 +30,15 @@ public class ConstructorUtil {
|
||||
* 构造对象缓存
|
||||
*/
|
||||
private static final WeakConcurrentMap<Class<?>, Constructor<?>[]> CONSTRUCTORS_CACHE = new WeakConcurrentMap<>();
|
||||
// --------------------------------------------------------------------------------------------------------- Constructor
|
||||
|
||||
/**
|
||||
* 清除方法缓存
|
||||
*/
|
||||
synchronized static void clearCache() {
|
||||
CONSTRUCTORS_CACHE.clear();
|
||||
}
|
||||
|
||||
// region ----- Constructor
|
||||
|
||||
/**
|
||||
* 查找类中的指定参数的构造方法,如果找到构造方法,会自动设置可访问为true
|
||||
@ -84,7 +92,9 @@ public class ConstructorUtil {
|
||||
return beanClass.getDeclaredConstructors();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------- newInstance
|
||||
// endregion
|
||||
|
||||
// region ----- newInstance
|
||||
|
||||
/**
|
||||
* 实例化对象<br>
|
||||
@ -131,4 +141,5 @@ public class ConstructorUtil {
|
||||
public static <T> T newInstanceIfPossible(final Class<T> type) {
|
||||
return PossibleObjectCreator.of(type).create();
|
||||
}
|
||||
// endregion
|
||||
}
|
||||
|
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) 2024. looly(loolly@aliyun.com)
|
||||
* Hutool is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* https://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
package org.dromara.hutool.core.reflect;
|
||||
|
||||
import org.dromara.hutool.core.array.ArrayUtil;
|
||||
import org.dromara.hutool.core.lang.Assert;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* 字段反射类<br>
|
||||
* 此类持有类中字段的缓存,如果字段在类中修改,则需要手动调用clearCaches方法清除缓存。
|
||||
*
|
||||
* @author Looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class FieldReflect {
|
||||
|
||||
/**
|
||||
* 创建FieldReflect
|
||||
*
|
||||
* @param clazz 类
|
||||
* @return FieldReflect
|
||||
*/
|
||||
public static FieldReflect of(final Class<?> clazz) {
|
||||
return new FieldReflect(clazz);
|
||||
}
|
||||
|
||||
private final Class<?> clazz;
|
||||
private volatile Field[] declaredFields;
|
||||
private volatile Field[] allFields;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param clazz 类
|
||||
*/
|
||||
public FieldReflect(final Class<?> clazz) {
|
||||
this.clazz = Assert.notNull(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前类
|
||||
*
|
||||
* @return 当前类
|
||||
*/
|
||||
public Class<?> getClazz() {
|
||||
return clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空缓存
|
||||
*/
|
||||
synchronized public void clearCaches() {
|
||||
declaredFields = null;
|
||||
allFields = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得当前类声明的所有字段(包括非public字段),但不包括父类的字段
|
||||
*
|
||||
* @param predicate 过滤器
|
||||
* @return 字段数组
|
||||
* @throws SecurityException 安全检查异常
|
||||
*/
|
||||
public Field[] getDeclaredFields(final Predicate<Field> predicate) {
|
||||
if (null == declaredFields) {
|
||||
synchronized (FieldReflect.class) {
|
||||
if (null == declaredFields) {
|
||||
declaredFields = clazz.getDeclaredFields();
|
||||
}
|
||||
}
|
||||
}
|
||||
return ArrayUtil.filter(declaredFields, predicate);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得当前类和父类声明的所有字段(包括非public字段)
|
||||
*
|
||||
* @param predicate 过滤器
|
||||
* @return 字段数组
|
||||
* @throws SecurityException 安全检查异常
|
||||
*/
|
||||
public Field[] getAllFields(final Predicate<Field> predicate) {
|
||||
if (null == allFields) {
|
||||
synchronized (FieldReflect.class) {
|
||||
if (null == allFields) {
|
||||
allFields = getFieldsDirectly(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ArrayUtil.filter(allFields, predicate);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得一个类中所有字段列表,直接反射获取,无缓存<br>
|
||||
* 如果子类与父类中存在同名字段,则这两个字段同时存在,子类字段在前,父类字段在后。
|
||||
*
|
||||
* @param withSuperClassFields 是否包括父类的字段列表
|
||||
* @return 字段列表
|
||||
* @throws SecurityException 安全检查异常
|
||||
*/
|
||||
public Field[] getFieldsDirectly(final boolean withSuperClassFields) throws SecurityException {
|
||||
Field[] allFields = null;
|
||||
Class<?> searchType = this.clazz;
|
||||
Field[] declaredFields;
|
||||
while (searchType != null) {
|
||||
declaredFields = searchType.getDeclaredFields();
|
||||
if (null == allFields) {
|
||||
allFields = declaredFields;
|
||||
} else {
|
||||
allFields = ArrayUtil.append(allFields, declaredFields);
|
||||
}
|
||||
searchType = withSuperClassFields ? searchType.getSuperclass() : null;
|
||||
}
|
||||
|
||||
return allFields;
|
||||
}
|
||||
}
|
@ -36,9 +36,29 @@ public class FieldUtil {
|
||||
/**
|
||||
* 字段缓存
|
||||
*/
|
||||
private static final WeakConcurrentMap<Class<?>, Field[]> FIELDS_CACHE = new WeakConcurrentMap<>();
|
||||
private static final WeakConcurrentMap<Class<?>, FieldReflect> FIELDS_CACHE = new WeakConcurrentMap<>();
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------- Field
|
||||
/**
|
||||
* 清除方法缓存
|
||||
*/
|
||||
synchronized static void clearCache() {
|
||||
FIELDS_CACHE.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为父类引用字段<br>
|
||||
* 当字段所在类是对象子类时(对象中定义的非static的class),会自动生成一个以"this$0"为名称的字段,指向父类对象
|
||||
*
|
||||
* @param field 字段
|
||||
* @return 是否为父类引用字段
|
||||
* @since 5.7.20
|
||||
*/
|
||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||
public static boolean isOuterClassField(final Field field) {
|
||||
return "this$0".equals(field.getName());
|
||||
}
|
||||
|
||||
// region ----- Field
|
||||
|
||||
/**
|
||||
* 查找指定类中是否包含指定名称对应的字段,包括所有字段(包括非public字段),也包括父类和Object类的字段
|
||||
@ -85,6 +105,18 @@ public class FieldUtil {
|
||||
return field.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取本类定义的指定名称的字段,包括私有字段,但是不包括父类字段
|
||||
*
|
||||
* @param beanClass Bean的Class
|
||||
* @param name 字段名称
|
||||
* @return 字段对象,如果未找到返回{@code null}
|
||||
*/
|
||||
public static Field getDeclearField(final Class<?> beanClass, final String name) {
|
||||
final Field[] fields = getDeclaredFields(beanClass, (field -> StrUtil.equals(name, field.getName())));
|
||||
return ArrayUtil.isEmpty(fields) ? null : fields[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找指定类中的指定name的字段(包括非public字段),也包括父类和Object类的字段, 字段不存在则返回{@code null}
|
||||
*
|
||||
@ -94,28 +126,13 @@ public class FieldUtil {
|
||||
* @throws SecurityException 安全异常
|
||||
*/
|
||||
public static Field getField(final Class<?> beanClass, final String name) throws SecurityException {
|
||||
final Field[] fields = getFields(beanClass);
|
||||
return ArrayUtil.firstMatch((field) -> name.equals(getFieldName(field)), fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取本类定义的指定名称的字段,包括私有字段,但是不包括父类字段
|
||||
*
|
||||
* @param beanClass Bean的Class
|
||||
* @param name 字段名称
|
||||
* @return 字段对象,如果未找到返回{@code null}
|
||||
*/
|
||||
public static Field getDeclearField(final Class<?> beanClass, final String name) {
|
||||
try {
|
||||
return beanClass.getDeclaredField(name);
|
||||
} catch (final NoSuchFieldException e) {
|
||||
return null;
|
||||
}
|
||||
final Field[] fields = getFields(beanClass, (field -> StrUtil.equals(name, field.getName())));
|
||||
return ArrayUtil.isEmpty(fields) ? null : fields[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定类中字段名和字段对应的有序Map,包括其父类中的字段<br>
|
||||
* 如果子类与父类中存在同名字段,则这两个字段同时存在,子类字段在前,父类字段在后。
|
||||
* 如果子类与父类中存在同名字段,则父类字段忽略
|
||||
*
|
||||
* @param beanClass 类
|
||||
* @return 字段名和字段对应的Map,有序
|
||||
@ -125,7 +142,7 @@ public class FieldUtil {
|
||||
final Field[] fields = getFields(beanClass);
|
||||
final HashMap<String, Field> map = MapUtil.newHashMap(fields.length, true);
|
||||
for (final Field field : fields) {
|
||||
map.put(field.getName(), field);
|
||||
map.putIfAbsent(field.getName(), field);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
@ -139,8 +156,7 @@ public class FieldUtil {
|
||||
* @throws SecurityException 安全检查异常
|
||||
*/
|
||||
public static Field[] getFields(final Class<?> beanClass) throws SecurityException {
|
||||
Assert.notNull(beanClass);
|
||||
return FIELDS_CACHE.computeIfAbsent(beanClass, (key) -> getFieldsDirectly(beanClass, true));
|
||||
return getFields(beanClass, null);
|
||||
}
|
||||
|
||||
|
||||
@ -155,7 +171,22 @@ public class FieldUtil {
|
||||
* @since 5.7.14
|
||||
*/
|
||||
public static Field[] getFields(final Class<?> beanClass, final Predicate<Field> fieldPredicate) throws SecurityException {
|
||||
return ArrayUtil.filter(getFields(beanClass), fieldPredicate);
|
||||
Assert.notNull(beanClass);
|
||||
return FIELDS_CACHE.computeIfAbsent(beanClass, FieldReflect::of).getAllFields(fieldPredicate);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得当前类声明的所有字段(包括非public字段),但不包括父类的字段<br>
|
||||
*
|
||||
* @param beanClass 类
|
||||
* @param fieldPredicate field过滤器,过滤掉不需要的field,{@link Predicate#test(Object)}为{@code true}保留,null表示全部保留
|
||||
* @return 字段列表
|
||||
* @throws SecurityException 安全检查异常
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static Field[] getDeclaredFields(final Class<?> beanClass, final Predicate<Field> fieldPredicate) throws SecurityException {
|
||||
Assert.notNull(beanClass);
|
||||
return FIELDS_CACHE.computeIfAbsent(beanClass, FieldReflect::of).getDeclaredFields(fieldPredicate);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -168,24 +199,13 @@ public class FieldUtil {
|
||||
* @throws SecurityException 安全检查异常
|
||||
*/
|
||||
public static Field[] getFieldsDirectly(final Class<?> beanClass, final boolean withSuperClassFields) throws SecurityException {
|
||||
Assert.notNull(beanClass);
|
||||
|
||||
Field[] allFields = null;
|
||||
Class<?> searchType = beanClass;
|
||||
Field[] declaredFields;
|
||||
while (searchType != null) {
|
||||
declaredFields = searchType.getDeclaredFields();
|
||||
if (null == allFields) {
|
||||
allFields = declaredFields;
|
||||
} else {
|
||||
allFields = ArrayUtil.append(allFields, declaredFields);
|
||||
}
|
||||
searchType = withSuperClassFields ? searchType.getSuperclass() : null;
|
||||
}
|
||||
|
||||
return allFields;
|
||||
return FieldReflect.of(beanClass).getFieldsDirectly(withSuperClassFields);
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region ----- Field Value
|
||||
|
||||
/**
|
||||
* 获取字段值
|
||||
*
|
||||
@ -343,15 +363,5 @@ public class FieldUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为父类引用字段<br>
|
||||
* 当字段所在类是对象子类时(对象中定义的非static的class),会自动生成一个以"this$0"为名称的字段,指向父类对象
|
||||
*
|
||||
* @param field 字段
|
||||
* @return 是否为父类引用字段
|
||||
* @since 5.7.20
|
||||
*/
|
||||
public static boolean isOuterClassField(final Field field) {
|
||||
return "this$0".equals(field.getName());
|
||||
}
|
||||
// endregion
|
||||
}
|
||||
|
@ -73,13 +73,8 @@ public class MethodReflect {
|
||||
allMethods = null;
|
||||
}
|
||||
|
||||
// region ----- getMathod
|
||||
// region ----- getMethods
|
||||
|
||||
|
||||
|
||||
// endregion
|
||||
|
||||
// region ----- getMathods
|
||||
/**
|
||||
* 获取当前类及父类的所有公共方法,等同于{@link Class#getMethods()}
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user