package com.zhgd.xmgl.util; import cn.hutool.core.util.StrUtil; import lombok.extern.slf4j.Slf4j; 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; /** * 方法引用获取属性名工具类 */ @Slf4j public class RefUtil { private static Map, Field> cache = new ConcurrentHashMap<>(); /** * 获取字段名列表 * * @param functions * @param * @param * @return */ public static List fieldNames(SerializableFunction... functions) { return Arrays.stream(functions).map(RefUtil::fieldName).collect(Collectors.toList()); } /** * 方法引用获取属性名并转成下划线 * * @param function * @param * @param * @return */ public static String fieldNameUlc(SerializableFunction function) { return StrUtil.toUnderlineCase(fieldName(function)); } /** * 方法引用获取属性名 * * @param function * @param * @param * @return */ public static String fieldName(SerializableFunction function) { Field field = RefUtil.getField(function); return field.getName(); } private static Field getField(SerializableFunction function) { return cache.computeIfAbsent(function, RefUtil::findField); } private static Field findField(SerializableFunction 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) { log.error("error:", e); } // 第5步 如果没有找到对应的字段应该抛出异常 if (field != null) { return field; } throw new NoSuchFieldError(fieldName); } }