104 lines
3.6 KiB
Java
104 lines
3.6 KiB
Java
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);
|
||
}
|
||
}
|