add FieldReflect

This commit is contained in:
Looly 2024-05-16 12:15:35 +08:00
parent 7ae93644e3
commit 8e4b24f8fa
4 changed files with 205 additions and 59 deletions

View File

@ -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
}

View File

@ -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;
}
}

View File

@ -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
}

View File

@ -73,13 +73,8 @@ public class MethodReflect {
allMethods = null;
}
// region ----- getMathod
// region ----- getMethods
// endregion
// region ----- getMathods
/**
* 获取当前类及父类的所有公共方法等同于{@link Class#getMethods()}
*