通过方法引用获取方法名

11 篇文章 0 订阅

在学习Mybatis-plus时,可以通过getter方法的方法引用来获取到对应的字段名

LambdaQueryWrapper<PurchaseOrder> wrapper = new LambdaQueryWrapper<>();
wrapper.like(PurchaseOrder::getBillTypeName, order.getBillTypeName());

这种情况避免了魔法值的出现,也不需要手动写死,避免因需求改变而导致的错误

QueryWrapper<OrderDataDTO> wrapper = new QueryWrapper<>();
wrapper.like("bill_type_name", dto.getBillTypeName())

lambda表达式不仅可以通过方法引用简化代码,也可以通过getter/setter的方法引用获取到对应的属性名,避免出现bug

代码实现

函数式接口

首先需要定义一个函数式接口来接受我们的方法引用,该接口必须要继承 Serializable 才能获取到方法信息

@FunctionalInterface
public interface SFunction<T> extends Serializable {
    /**
     * 获取对象属性信息
     *
     * @param source
     * @return
     */
    Object get(T source);
}

函数式接口:如果一个接口中只有一个抽象方法(可以包含多个默认方法或多个static方法),那么该接口就是函数式接口。本质上是将函数的实现直接转换为了一个声明语句的定义,极大简化了原有的实现方式

@FunctionalInterface:用来指定某个接口必须是函数式接口,所以该注解只能修饰接口,加上标注, 则会触发JavaCompiler的检查。对于符合函数接口的接口,加不加都无关紧要,但是加上则会提供一层编译检查的保障。如果不符合,则会报错。

工具类

解析Function获取字段属性名

public class ConvertUtil {

    public static final String GET = "get";

    public static final String IS = "is";

    private static final Map<Class<?>, SerializedLambda> CLASS_LAMBDA_CACHE = new ConcurrentHashMap<>();

    /**
     * 转换方法引用为属性名
     *
     * @param fn
     * @param <T>
     * @return
     */
    public static <T> String convertToFieldName(SFunction<T> fn) {
        SerializedLambda lambda = getSerializedLambda(fn);
        String methodName = lambda.getImplMethodName();
        if (methodName.startsWith(GET)) {
            methodName = methodName.substring(3);
        } else if (methodName.startsWith(IS)) {
            methodName = methodName.substring(2);
        } else {
            throw new IllegalArgumentException("无效的getter方法:" + methodName);
        }
        return StringUtil.firstToLowerCase(methodName);
    }

    public static SerializedLambda getSerializedLambda(Serializable fn) {
        SerializedLambda lambda = CLASS_LAMBDA_CACHE.get(fn.getClass());
        // 先检查缓存中是否存在
        if (lambda == null) {
            try {
                // 提取SerializedLambda并缓存
                Method method = fn.getClass().getDeclaredMethod("writeReplace");
                method.setAccessible(Boolean.TRUE);
                lambda = (SerializedLambda) method.invoke(fn);
                CLASS_LAMBDA_CACHE.put(fn.getClass(), lambda);
            } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
        return lambda;
    }
}
/**
 * 首字母转换小写
 *
 * @param str 需要转换的字符串
 * @return 转换好的字符串
 */
public static String firstToLowerCase(final String str) {
    if (isBlank(str)) {
        return EMPTY;
    }
    return str.substring(0, 1).toLowerCase() + str.substring(1);
}

测试

public static void main(String[] args) {
    String firstNameFieldNameStyle = ConvertUtil.convertToFieldName(User::getFirstName);
    String firstNameUnderlineStyle = ConvertUtil.convertToUnderline(User::getFirstName);
    System.out.println("firstNameFieldNameStyle:" + firstNameFieldNameStyle);
    System.out.println("firstNameUnderlineStyle:" + firstNameUnderlineStyle);
}

 

想要深入研究的可以看这个链接:Lambda表达式获取传入的方法引用的方法名_社恐Coder的博客-CSDN博客

1. 获取返回值类型 在AspectJ中,可以使用`JoinPoint`对象的`getSignature()`方法获取到当前执行的方法的签信息,进而获取方法的返回类型。具体代码如下: ```java @AfterReturning(pointcut = "execution(* com.example.demo.service.UserService.getUser(..))", returning = "result") public void afterReturning(JoinPoint joinPoint, Object result) { Signature signature = joinPoint.getSignature(); if (signature instanceof MethodSignature) { MethodSignature methodSignature = (MethodSignature) signature; Class<?> returnType = methodSignature.getReturnType(); System.out.println("返回类型:" + returnType.getName()); } } ``` 2. Lambda表达式获取传入的方法引用方法 Lambda表达式可以通过方法引用来传递方法引用,如果需要获取这个方法方法,可以使用Java8中添加的`MethodReference`类来实现。具体代码如下: ```java public interface UserService { void addUser(User user); } public class UserServiceImpl implements UserService { @Override public void addUser(User user) { System.out.println("addUser调用成功"); } } public class UserController { private UserService userService; public void setUserService(UserService userService) { this.userService = userService; } public void addUser(User user) { userService.addUser(user); } } public class MyAspect { @Before("execution(* com.example.demo.controller.UserController.addUser(..)) && args(user)") public void beforeAddUser(User user) { MethodReference<UserService> methodReference = UserService::addUser; String methodName = methodReference.getName(); System.out.println("方法:" + methodName); } } ``` 在`MyAspect`切面中,通过Lambda表达式将`UserService::addUser`传递给`MethodReference`类,然后通过`getName()`方法获取方法。需要注意的是,这个方法是`UserService.addUser`而不是`UserServiceImpl.addUser`,因为`MethodReference`是根据接口中的方法获取方法的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值