How to write a pointcut aspect based on annotated parameter

I am having a little problem with how to create a pointcut that will work on beans that has a specific annotated parameter. My ultimate goal is to check the parameter value before processing it, but for now I just need to create a pointcut.

Consider the following annotation

@Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.PARAMETER }) public @interface MyAnnotation {} 

I would like to apply this to several methods, for example:

 public void method1(@MyAnnotation long i) {} public void method2(String someThing, @MyAnnotation long i) {} public void method3(String someThing, @MyAnnotation long i, byte value) {} 

So,

  • I don't care which class (or package) are in
  • The position of the annotated argument will be different.
  • I know that annotated value will only apply to a specific type

My pointcut implementation should be something like:

 @Before(value = "* *(..) && args(verifyMe)") public void verifyInvestigationId(long verifyMe) {} 

I got a little confused about what @Before should @Before and how to relate the annotation and its type. At the moment, this is probably not worth listing the things I tried!

Refresh . Based on the recommendations I saw at http://stackoverflow.com/questions/3565718/pointcut-matching-methods-with-annotated-parameters/3567170#3567170 (and fixing a couple of misunderstandings and adding space that I forgot) I got until the following works:

 @Before("execution(public * *(.., @full.path.to.MyAnnotation (*), ..))") public void beforeMethod(JoinPoint joinPoint) { System.out.println("At least one of the parameters are annotated with @MyAnnotation"); } 

This is almost what I need - all I need to do is pass the value of the annotated argument as a parameter to the method. I cannot fully work out the syntax to get Spring for this (the linked answer does not show this).

+5
source share
2 answers

Very similar to my answer, which sheltem already pointed out, the solution looks like this (this time in annotation style syntax, because in Spring AOP you cannot use AspectJ's own syntax):

Original poster abstract:

 package annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.PARAMETER }) public @interface MyAnnotation {} 

Driver App:

I am using a driver application to test my AspectJ solution. In Spring, the class, as well as the aspect, must be Spring components / components for this to work.

 package de.scrum_master.app; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import annotations.MyAnnotation; public class Application { public void method1(@MyAnnotation int i) {} public void method2(String id, @MyAnnotation float f) {} public void method3(int i, @MyAnnotation List<String> strings, @MyAnnotation String s) {} public void method4(int i, @MyAnnotation Set<Integer> numbers, float f, boolean b) {} public void method5(boolean b, String s, @MyAnnotation String s2, float f, int i) {} public void notIntercepted(boolean b, String s, String s2, float f, int i) {} public static void main(String[] args) { List<String> strings = new ArrayList<String>(); strings.add("foo"); strings.add("bar"); Set<Integer> numbers = new HashSet<Integer>(); numbers.add(11); numbers.add(22); numbers.add(33); Application app = new Application(); app.method1(1); app.method2("foo", 1f); app.method3(1, strings, "foo"); app.method4(1, numbers, 1f, true); app.method5(false, "foo", "bar", 1f, 1); app.notIntercepted(false, "foo", "bar", 1f, 1); } } 

aspect:

 package de.scrum_master.aspect; import java.lang.annotation.Annotation; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.SoftException; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.reflect.MethodSignature; import annotations.MyAnnotation; @Aspect public class ArgCatcherAspect { @Before("execution(public * *(.., @MyAnnotation (*), ..))") public void interceptMethodsWithAnnotatedParameters(JoinPoint thisJoinPoint) { System.out.println(thisJoinPoint); MethodSignature signature = (MethodSignature) thisJoinPoint.getSignature(); String methodName = signature.getMethod().getName(); Class<?>[] parameterTypes = signature.getMethod().getParameterTypes(); Annotation[][] annotations; try { annotations = thisJoinPoint.getTarget().getClass(). getMethod(methodName, parameterTypes).getParameterAnnotations(); } catch (Exception e) { throw new SoftException(e); } int i = 0; for (Object arg : thisJoinPoint.getArgs()) { for (Annotation annotation : annotations[i]) { if (annotation.annotationType() == MyAnnotation.class) { System.out.println(" " + annotation + " -> " + arg); // Verify 'arg' here or do whatever } } i++; } } } 

Console Log:

 execution(void de.scrum_master.app.Application.method1(int)) @annotations.MyAnnotation() -> 1 execution(void de.scrum_master.app.Application.method2(String, float)) @annotations.MyAnnotation() -> 1.0 execution(void de.scrum_master.app.Application.method3(int, List, String)) @annotations.MyAnnotation() -> [foo, bar] @annotations.MyAnnotation() -> foo execution(void de.scrum_master.app.Application.method4(int, Set, float, boolean)) @annotations.MyAnnotation() -> [33, 22, 11] execution(void de.scrum_master.app.Application.method5(boolean, String, String, float, int)) @annotations.MyAnnotation() -> bar 
+7
source

Here is what I ended up after playing with it (import skipped):

 @Aspect public class VerifyAspect { @Before("execution(* *(.., @annotations.MyAnnotation (*), ..)) && args(.., verifyMe)") public void verifyInvestigationId(final Object verifyMe) { System.out.println("Aspect verifying: " + verifyMe); } } 

There is no need for anything Spring specific, as AspectJ already provides you with options if necessary.

+1
source

All Articles