275 lines
8.1 KiB
Java
275 lines
8.1 KiB
Java
package com.imyeyu.java.ref;
|
|
|
|
import java.lang.reflect.Field;
|
|
import java.lang.reflect.Method;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* 反射工具类,提供字段与方法查找、字段读写、字符串转枚举等能力
|
|
*
|
|
* @author 夜雨
|
|
* @since 2023-05-04 15:05
|
|
*/
|
|
public class Ref {
|
|
|
|
/**
|
|
* 获取指定类声明的字段列表(不包含父类)
|
|
*
|
|
* @param clazz 类型对象
|
|
* @return 字段列表
|
|
*/
|
|
public static List<Field> listFields(Class<?> clazz) {
|
|
return List.of(clazz.getDeclaredFields());
|
|
}
|
|
|
|
/**
|
|
* 获取指定类及其父类声明的字段列表(直到 {@link Object} 之前)
|
|
*
|
|
* @param clazz 类型对象
|
|
* @return 字段列表
|
|
*/
|
|
public static List<Field> listAllFields(Class<?> clazz) {
|
|
List<Field> result = new ArrayList<>();
|
|
while (clazz != null && clazz != Object.class) {
|
|
Collections.addAll(result, clazz.getDeclaredFields());
|
|
clazz = clazz.getSuperclass();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* 将外部键名转换为 Java 字段名
|
|
*
|
|
* @param keyName 外部键名,支持中划线、下划线和空格分隔
|
|
* @return 驼峰命名字段名
|
|
*/
|
|
public static String getFieldName(String keyName) {
|
|
String[] splits = {"-", "_", " "};
|
|
StringBuilder full = new StringBuilder(keyName.substring(0, 1).toUpperCase() + keyName.substring(1));
|
|
for (String split : splits) {
|
|
if (keyName.contains(split)) {
|
|
// 存在分隔符时,先按分隔符拆词,再按驼峰拼接
|
|
full.setLength(0);
|
|
String[] word = keyName.split(split);
|
|
for (String s : word) {
|
|
full.append(s.substring(0, 1).toUpperCase()).append(s.substring(1));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return String.valueOf(full.charAt(0)).toLowerCase() + full.substring(1);
|
|
}
|
|
|
|
/**
|
|
* 反射获取对象字段,包括父级类,直至 {@link Object},如果都不存在则抛出异常
|
|
*
|
|
* @param clazz 类
|
|
* @param fieldName 字段名
|
|
* @return 字段对象
|
|
* @throws NullPointerException 找不到字段时抛出异常
|
|
*/
|
|
public static Field getField(Class<?> clazz, String fieldName) {
|
|
do {
|
|
try {
|
|
Field field = clazz.getDeclaredField(fieldName);
|
|
field.setAccessible(true);
|
|
return field;
|
|
} catch (NoSuchFieldException e) {
|
|
clazz = clazz.getSuperclass();
|
|
}
|
|
} while (clazz != Object.class);
|
|
throw new NullPointerException("not found field: %s in %s".formatted(fieldName, clazz));
|
|
}
|
|
|
|
/**
|
|
* 反射获取对象字段值,包括父级类,直至 {@link Object}
|
|
*
|
|
* @param object 对象
|
|
* @param fieldName 字段名
|
|
* @param toClass 返回类
|
|
* @param <T> 返回类型
|
|
* @return 字段值
|
|
* @throws IllegalAccessException 反射访问失败
|
|
* @throws NullPointerException 向上反射直至 {@link Object} 也找不到该字段
|
|
*/
|
|
public static <T> T getFieldValue(Object object, String fieldName, Class<? extends T> toClass) throws IllegalAccessException, NullPointerException {
|
|
return getFieldValue(object, getField(object.getClass(), fieldName), toClass);
|
|
}
|
|
|
|
/**
|
|
* 反射获取对象字段值
|
|
*
|
|
* @param object 对象
|
|
* @param field 字段
|
|
* @param toClass 返回类
|
|
* @param <T> 返回类型
|
|
* @return 字段值
|
|
* @throws IllegalAccessException 反射访问失败
|
|
* @throws NullPointerException 字段对象为空
|
|
*/
|
|
public static <T> T getFieldValue(Object object, Field field, Class<? extends T> toClass) throws IllegalAccessException, NullPointerException {
|
|
if (field == null) {
|
|
throw new NullPointerException("field can not be null");
|
|
}
|
|
field.setAccessible(true);
|
|
return toClass.cast(field.get(object));
|
|
}
|
|
|
|
/**
|
|
* 反射获取类字段
|
|
*
|
|
* @param objectClass 类
|
|
* @param fieldName 字段名
|
|
* @return 字段对象,不存在时返回 null
|
|
*/
|
|
public static Field getClassField(Class<?> objectClass, String fieldName) {
|
|
try {
|
|
Field field = objectClass.getDeclaredField(fieldName);
|
|
field.setAccessible(true);
|
|
return field;
|
|
} catch (NoSuchFieldException e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 反射获取指定类字段值
|
|
*
|
|
* @param object 对象
|
|
* @param objectClass 类
|
|
* @param fieldName 字段名
|
|
* @param toClass 值类型
|
|
* @param <T> 值类型
|
|
* @return 字段值
|
|
* @throws IllegalAccessException 反射访问失败
|
|
* @throws NoSuchFieldException 字段不存在
|
|
*/
|
|
public static <T> T getClassFieldValue(Object object, Class<?> objectClass, String fieldName, Class<T> toClass) throws IllegalAccessException, NoSuchFieldException {
|
|
Field field = getClassField(objectClass, fieldName);
|
|
if (field == null) {
|
|
throw new NoSuchFieldException("not found " + fieldName + " field in " + objectClass.getSimpleName());
|
|
}
|
|
field.setAccessible(true);
|
|
return toClass.cast(field.get(object));
|
|
}
|
|
|
|
/**
|
|
* 反射设置对象字段值,包括父级类,直至 {@link Object}
|
|
*
|
|
* @param object 对象
|
|
* @param fieldName 字段名
|
|
* @param value 字段值
|
|
* @throws IllegalAccessException 反射访问失败
|
|
*/
|
|
public static void setFieldValue(Object object, String fieldName, Object value) throws IllegalAccessException {
|
|
setFieldValue(object, getField(object.getClass(), fieldName), value);
|
|
}
|
|
|
|
/**
|
|
* 反射设置对象字段值
|
|
*
|
|
* @param object 对象
|
|
* @param field 字段对象
|
|
* @param value 字段值
|
|
* @throws IllegalAccessException 反射访问失败
|
|
*/
|
|
public static void setFieldValue(Object object, Field field, Object value) throws IllegalAccessException {
|
|
field.setAccessible(true);
|
|
field.set(object, value);
|
|
}
|
|
|
|
/**
|
|
* 反射设置对象字段值
|
|
*
|
|
* @param object 对象
|
|
* @param objectClass 类
|
|
* @param fieldName 字段名
|
|
* @param value 字段值
|
|
* @throws IllegalAccessException 反射访问失败
|
|
* @throws NullPointerException 字段不存在
|
|
*/
|
|
public static void setClassFieldValue(Object object, Class<?> objectClass, String fieldName, Object value) throws IllegalAccessException, NullPointerException {
|
|
Field field = getClassField(objectClass, fieldName);
|
|
if (field == null) {
|
|
throw new NullPointerException("not found " + fieldName + " field in " + objectClass.getSimpleName() + " class");
|
|
}
|
|
field.setAccessible(true);
|
|
field.set(object, value);
|
|
}
|
|
|
|
/**
|
|
* 反射查找方法,包括父级类,直至 {@link Object},如果都不存在则返回 null
|
|
*
|
|
* @param clazz 类
|
|
* @param methodName 方法名
|
|
* @param parameterTypes 可选参
|
|
* @return 方法对象,不存在时返回 null
|
|
* @throws NullPointerException 类对象为空
|
|
*/
|
|
public static Method getMethod(Class<?> clazz, String methodName, Class<?>... parameterTypes) {
|
|
if (clazz == null) {
|
|
throw new NullPointerException("class can not be null");
|
|
}
|
|
do {
|
|
try {
|
|
Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
|
|
method.setAccessible(true);
|
|
return method;
|
|
} catch (NoSuchMethodException e) {
|
|
clazz = clazz.getSuperclass();
|
|
}
|
|
} while (clazz != Object.class);
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* 字符串转枚举
|
|
*
|
|
* @param clazz 枚举类
|
|
* @param string 字符串
|
|
* @param <T> 泛型
|
|
* @return 匹配到的枚举值,找不到或输入为空时返回 null
|
|
* @throws IllegalArgumentException 传入类型不是枚举类型
|
|
*/
|
|
public static <T extends Enum<?>> T toType(Class<T> clazz, String string) {
|
|
if (string == null) {
|
|
return null;
|
|
}
|
|
T[] ts = clazz.getEnumConstants();
|
|
if (ts == null) {
|
|
throw new IllegalArgumentException(clazz.getName() + " is not an enum type");
|
|
}
|
|
for (T t : ts) {
|
|
if (t.name().equalsIgnoreCase(string)) {
|
|
return t;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* 创建字段反射元信息对象
|
|
*
|
|
* @param owner 字段所属类型
|
|
* @param keyName 字段键名
|
|
* @return 字段反射元信息
|
|
*/
|
|
public static RefField field(Class<?> owner, String keyName) {
|
|
return new RefField(owner, keyName);
|
|
}
|
|
|
|
/**
|
|
* 通过无参构造器创建实例
|
|
*
|
|
* @param type 类型对象
|
|
* @param <T> 泛型类型
|
|
* @return 新实例
|
|
* @throws Exception 反射创建实例异常
|
|
*/
|
|
public static <T> T newInstance(Class<T> type) throws Exception {
|
|
return type.getDeclaredConstructor().newInstance();
|
|
}
|
|
}
|