2023-10-16 15:07:51 +08:00

104 lines
3.6 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.zhgd.xmgl.util;
import cn.hutool.core.util.StrUtil;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import java.beans.Introspector;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
* 方法引用获取属性名工具类
*/
public class RefUtil {
private static Map<SerializableFunction<?, ?>, Field> cache = new ConcurrentHashMap<>();
/**
* 获取字段名列表
*
* @param functions
* @param <T>
* @param <R>
* @return
*/
public static <T, R> List<String> fieldNames(SerializableFunction<T, R>... functions) {
return Arrays.stream(functions).map(RefUtil::fieldName).collect(Collectors.toList());
}
/**
* 方法引用获取属性名并转成下划线
*
* @param function
* @param <T>
* @param <R>
* @return
*/
public static <T, R> String fieldNameUlc(SerializableFunction<T, R> function) {
return StrUtil.toUnderlineCase(fieldName(function));
}
/**
* 方法引用获取属性名
*
* @param function
* @param <T>
* @param <R>
* @return
*/
public static <T, R> String fieldName(SerializableFunction<T, R> function) {
Field field = RefUtil.getField(function);
return field.getName();
}
private static <T, R> Field getField(SerializableFunction<T, R> function) {
return cache.computeIfAbsent(function, RefUtil::findField);
}
private static <T, R> Field findField(SerializableFunction<T, R> function) {
Field field = null;
String fieldName = null;
try {
// 第1步 获取SerializedLambda
Method method = function.getClass().getDeclaredMethod("writeReplace");
method.setAccessible(Boolean.TRUE);
SerializedLambda serializedLambda = (SerializedLambda) method.invoke(function);
// 第2步 implMethodName 即为Field对应的Getter方法名
String implMethodName = serializedLambda.getImplMethodName();
if (implMethodName.startsWith("get") && implMethodName.length() > 3) {
fieldName = Introspector.decapitalize(implMethodName.substring(3));
} else if (implMethodName.startsWith("is") && implMethodName.length() > 2) {
fieldName = Introspector.decapitalize(implMethodName.substring(2));
} else if (implMethodName.startsWith("lambda$")) {
throw new IllegalArgumentException("SerializableFunction不能传递lambda表达式,只能使用方法引用");
} else {
throw new IllegalArgumentException(implMethodName + "不是Getter方法引用");
}
// 第3步 获取的Class是字符串并且包名是“/”分割,需要替换成“.”才能获取到对应的Class对象
String declaredClass = serializedLambda.getImplClass().replace("/", ".");
Class<?> aClass = Class.forName(declaredClass, false, ClassUtils.getDefaultClassLoader());
// 第4步 Spring 中的反射工具类获取Class中定义的Field
field = ReflectionUtils.findField(aClass, fieldName);
} catch (Exception e) {
e.printStackTrace();
}
// 第5步 如果没有找到对应的字段应该抛出异常
if (field != null) {
return field;
}
throw new NoSuchFieldError(fieldName);
}
}