Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

spring AoP, pointcut expression for overloaded methods with same parameter types

I've defined a class for CRUD operations on comments. The read method is overloaded.

class Comment{
    // method 1: returns all the comments by a user
    findAll(long userId, long subjectId, String param);

    // method 2: returns all the comments of all the users
    findAll(long subjectId, String param)
}

The point cut expression I've tried is

@Around("execution(* com.package..*Controller.findAll(..)) && args(userId,subjectId,..)")
public Object validateFindAll(final ProceedingJoinPoint proceedingJoinPoint, final long userId, final long subjectId) {
    // validate userId, if available
    // validate subjectId
}

Problem: As the data types for userId and subjectId are same, the point expression when applied to method 2 shifts the param values by 1 place. This means, the expression does not understand that the first parameter userId isn't passed. Instead, userId gets 'subjectId' as value and the subjectId gets the adjacent parameter 'param' as its value.

Note

  1. I am trying to avoid writing another method like findUserComments().

  2. I want to maintain consistency across the application. There are other classes with similar patterns of CRUD operations.

Question: Is it possible to define an expression applicable to both the methods with the first parameter userId being optional ?

EDIT - Solution While I was playing around with different approaches as suggested in the solutions below, I've finally removed method 2. I handle that case in method 1.

like image 316
Tushar Mishra Avatar asked Jan 17 '26 10:01

Tushar Mishra


1 Answers

You cannot explicitly bind an AspectJ parameter and then expect it to match an incompatible signature. Thus, your pointcut will only match findAll(long, long, ..), i.e. "method 1" in your example. You can specify optional arguments with .., but then you cannot bind them to named parameters.

For example, it is possible to match both methods and bind long subjectId and String param via args(.., subjectId, param) because both parameters are predictably right-aligned at the end of the signature. If you want any optional (and thus unbound) parameter, you need to use thisJoinPoint.getArgs():

@Around("execution(* com.package..*Controller.findAll(..)) && args(.., subjectId, param)")
public Object validateFindAll(
    final ProceedingJoinPoint thisJoinPoint,
    final long subjectId,
    final String param
) {
    if (thisJoinPoint.getArgs().length == 3)
        System.out.println(thisJoinPoint + " -> " + thisJoinPoint.getArgs()[0] + ", " + subjectId + ", " + param);
    else
        System.out.println(thisJoinPoint + " -> " + subjectId + ", " + param);
    // (...)
}

But while getArgs() is dynamic, it probably is slower than parameter binding because it uses reflection. Maybe having two pointcuts is not so bad after all. If your advice method does complicated things before/after proceed(), you can still factor those things out into helper methods and call them from both advice.

like image 188
kriegaex Avatar answered Jan 20 '26 23:01

kriegaex



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!