0

I have read the following valuable links:

Consider this request for a setter method

public void setSomething(@ParameterLevel(name="abc") String something){
   this.something = something;
}

I have the following and works fine:

@Pointcut("execution(* *.*(@somepackage.ParameterLevel (*)))")
void parameterLevel01() {}

Now I want retrieve the @ParameterLevel annotation through a method's parameter such as the following:

@Pointcut("execution(* *.*(@somepackage.ParameterLevel (*)))")
void parameterLevel01(ParameterLevel parameterLevel) {} <--To be used directly in the advice method

The purpose is use the Annotation directly how a parameter in the advice method

Something similar such as:

@within(classLevel) for @ClassLevel in:

@ClassLevel
public class SomeClass {
  ...
}

@annotation(methodLevel) for @MethodLevel in:

   @MethodLevel
   public void somethingToDo(){
     ...
   }

How accomplish this goal. Is possible? I am working with AspectJ 1.9.6

kriegaex
  • 63,017
  • 15
  • 111
  • 202
Manuel Jordan
  • 15,253
  • 21
  • 95
  • 158
  • I don't understand why you are asking this question here. You read the other questions of which this is a duplicate already and I guess you also read my two accepted answers. Do you really think that if a simple way of binding parameter annotations to advice method parameters like the one you wish for was possible, I would have posted the more complex ones? – kriegaex Sep 15 '20 at 04:40
  • Besides, using `.., something, ..` in a signature implies that `something` can occur multiple times, so binding it to a single value parameter would be ambiguous. You could imagine binding it to an array instead, but this is impossible as of today (AspectJ 1.9.6). So just use my solutions, please. Thank you. – kriegaex Sep 15 '20 at 04:42
  • `.., something, ..` was updated to be removed. Now is about to only one parameter. Furthermore, in the end of my post say `How accomplish this goal. Is possible?` I can assume that for a new release of AspectJ that support or feature was added. – Manuel Jordan Sep 15 '20 at 13:56
  • `You read the other questions of which this is a duplicate already and I guess you also read my two accepted answers` my question is not a duplicate, in that posts there is no a request to retrieve the annotation how a Parameter directly in the advice method, it is only about to apply a poincut to a method with a parameter annotated. Is not the same – Manuel Jordan Sep 15 '20 at 13:59
  • You edited your question 9 hours **after** my comment. Anyway, this question was a duplicate before and for the most part still is. Your question is implicitly answered in the other questions. BTW, if you want to know if there is a new feature in AspectJ, I think you should read the release notes rather than post a duplicate question every time a new release comes out or just ask in a comment under the other question if there are any news about this. FWIW, I am going to answer again here if it makes you happy. – kriegaex Sep 16 '20 at 00:41
  • Like I said `How accomplish this goal. Is possible?` and if yes, the answer posted in this network helps for any other developer with the similar situation. And in the future, if that feature is implemented then here can be updated the answer too. Not always the answers are updated when a new feature available. And this case is not necessary a functional sample code. And in your answer you are adding more information about that the same feature was requested before. `You edited your question 9 hours after my comment` Yes, I was very tired to realize about that line. – Manuel Jordan Sep 16 '20 at 13:50
  • 1
    And like I said, the answer was in the other questions you already found. My answer here is kinda redundant, just a variant of what was there already. It is just a courtesy to you. You are lucky I had to kill some time at an airport, waiting for a connecting flight. – kriegaex Sep 16 '20 at 15:35
  • Really I appreciate your support. Thanks for your time. Your answers are valuable. Stay Safe – Manuel Jordan Sep 16 '20 at 16:03

1 Answers1

1

No matter if you use .., @MyAnnotation (*), .. or just @MyAnnotation (*), which only removes the ambiguity of possibly multiple matches, there is no direct way to bind a method argument annotation to an advice argument, only the method argument itself. This has not changed in AspectJ. You would have seen it mentioned in the release notes otherwise, because it would be a new feature.

So you will have to use the method from my other two answers which you have already linked to in your question, i.e. iterating over parameter types and annotations manually.

Somewhat off-topic, there is a very old Bugzilla ticket #233718 which is about binding multiple matched (annotated) parameters, but not about binding their annotations. It came up in a recent discussion I had with AspectJ maintainer Andy Clement. But even if this was implemented one day, it would not solve your problem.

I think you can take it from here and adapt my solution from the linked questions to your needs. Feel free to let me know if you have any follow-up questions about that, but it should be pretty straightforward. You might be able to optimise because you know the exact parameter position (think array index), if you feel so inclined, i.e. you don't need to iterate over all parameters.


Update: Here is a little MCVE for you. It is based on this answer and has been simplified to assume the annotation is always on the first parameter and the first parameter only.

Please learn what an MCVE is and provide one by yourself next time because it is your job, not mine. This was your free shot.

Marker annotation + driver application:

package de.scrum_master.app;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;

@Retention(RUNTIME)
public @interface ParameterLevel {
  String name();
}
package de.scrum_master.app;

public class Application {
  public static void main(String[] args) {
    new Application().doSomething("foo");
  }

  public void doSomething(@ParameterLevel(name="abc") String string) {}
}

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 de.scrum_master.app.ParameterLevel;

@Aspect
public class ParameterLevelAspect {
  @Before("execution(public * *(@de.scrum_master.app.ParameterLevel (*))) && args(string)")
  public void beforeAdvice(JoinPoint thisJoinPoint, String string) {
    System.out.println(thisJoinPoint + " -> " + string);
    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()[0];
    } catch (NoSuchMethodException | SecurityException e) {
      throw new SoftException(e);
    }
    ParameterLevel parameterLevel = null;
    for (Annotation annotation : annotations) {
      if (annotation.annotationType() == ParameterLevel.class) {
        parameterLevel = (ParameterLevel) annotation;
        break;
      }
    }
    assert parameterLevel != null;
    System.out.println("  " + parameterLevel + " -> " + parameterLevel.name());
  }
}

Console log:

execution(void de.scrum_master.app.Application.doSomething(String)) -> foo
  @de.scrum_master.app.ParameterLevel(name="abc") -> abc
kriegaex
  • 63,017
  • 15
  • 111
  • 202