Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I need a pointcut for methods in classes annotated with @X or methods annotated with @X. I also need the annotation object. If both the class and the method are annotated I prefer to get the method annotation as argument.

I tried the following, which creates an "inconsistent binding" warning. (Why not just set them null?)

@Around("@annotation(methodLevelX) || @within(classLevelX)")
public Object advise(ProceedingJoinPoint pjp, X methodLevelX, X classLevelX)

The following creates a "ambiguous binding of parameter(s) x across '||' in pointcut" warning. (Which does not necessarily make sense in my opinion: Why not bind the first short circuited evaluation?)

@Around("@annotation(x) || @within(x)")
public Object advise(ProceedingJoinPoint pjp, X x)

Splitting the previous attempt in two naturally results in two method calls if class and method annotations are present.

I know I could just get the method and class with reflection and my desired annotation with a pointcut like this:

@Around("@annotation(com.package.X) || @within(com.package.X)")

But I'd prefer not to.

Is there any "one pointcut, one method, one annotation argument", solution for my requirement that does not require reflection?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
324 views
Welcome To Ask or Share your Answers For Others

1 Answer

Not quite, but almost. You will need two pointcuts, two advices, but you can delegate the work to a single method. Here's how it would look like:

@Aspect
public class AnyAspectName {

    @Pointcut("execution(@X * *.*(..))")
    void annotatedMethod() {}

    @Pointcut("execution(* (@X *).*(..))")
    void methodOfAnnotatedClass() {}

    @Around("annotatedMethod() && @annotation(methodLevelX)")
    public Object adviseAnnotatedMethods(ProceedingJoinPoint pjp, X methodLevelX) 
            throws Throwable {
        return aroundImplementation(pjp, methodLevelX);
    }

    @Around("methodOfAnnotatedClass() && !annotatedMethod() && @within(classLevelX)")
    public Object adviseMethodsOfAnnotatedClass(ProceedingJoinPoint pjp, X classLevelX) 
            throws Throwable {
        return aroundImplementation(pjp, classLevelX);
    }

    public Object aroundImplementation(ProceedingJoinPoint pjp, X annotation) 
            throws Throwable {
        return pjp.proceed();
    }

}

Note that besides splitting apart the @annotation() and @within() pointcuts, I added restrictions to the resulting pointcuts so that they aren't too broad. I suppose you want method execution join points, so I added the needed pointcut expressions that would restrict it to method execution. They are matching

  1. execution of any method annotated with @X with any return type in any class being in any package for the first advice
  2. execution of any method with any return type in any class annotated with @X for the second.

Further restricting @within(X) and @annotation(X) comes in handy, because @within(X) by itself would match

any join point where the associated code is defined in a type with an annotation of type X

which would include method-execution, method-call, constructor-execution, constructor-call, pre-initialization, static initialization, initialization, field set, field get, exception-handler, lock type join points (not all join points are valid for around advices though). Similarly, @annotation(X) by itself would mean

any join point where the subject has an annotation of type X

which could also mean most of the previously mentioned join points, depending on the target type of your annotation.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...