Search code examples
javaannotationsaspectj

Annotation on member and Aspectj


I would like to be able to annotate a member of my class and then set up Around pointcuts which trigger on its get and set methods. Rough example:

public class Point {
   @Monitor
   private int x;

   public int getX() { return x;}
   public void setX(int v) {x = v; }
}
@Aspect
public class MonitorAspect {
   @Around("annotation(Monitor) && ???)
   public void actionOnGet(ProceedingJoinPoint jp) {
      // do stuff related to get
   }

   @Around("annotation(Monitor) && ???)
   public void actionOnSet(ProceedingJoinPoint jp) {
      // do stuff related to set
   }
}

Is that possible? Thanks for any info.


Solution

  • Your question is not very specific. For example, do you wish to intercept

    1. any read/write field access (from inside getters or elsewhere in the code),
    2. getter/setter execution in general,
    3. read/write field access, but only directly from within getter/setter methods,
    4. read/write field access from within getter/setter methods including (helper) methods called by getters/setters,
    5. something else?

    I am going to assume option 1.

    I also have no idea what

    // do stuff related to get
    

    is supposed to mean. What exactly that "stuff" is, determines what kind of advice (before, after, around) you should use and how to implement that advice. Henceforth, I am going to assume you simply want to log that the field read/write access happened, not logging any field values as such. If you need anything more sophisticated, I have no idea, because you just call it "stuff".

    So here is a simple MCVE:

    import static java.lang.annotation.RetentionPolicy.RUNTIME;
    import java.lang.annotation.Retention;
    
    @Retention(RUNTIME)
    public @interface Monitor { }
    
    public class Point {
      @Monitor
      private int x;
    
      public int getX() { return x; }
      public void setX(int v) { x = v; }
    
      public static void main(String[] args) {
        Point p = new Point();
        // Indirect read/write access using setter/getter
        p.setX(11);
        System.out.println(p.getX());
    
        // Direct read/write access
        p.x = 22;
        System.out.println(p.x);
      }
    }
    
    import org.aspectj.lang.JoinPoint.EnclosingStaticPart;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    
    @Aspect
    class MonitorAspect {
      @Around("get(@Monitor * *)")
      public Object actionOnGet(ProceedingJoinPoint jp, EnclosingStaticPart enclosingStaticPart) throws Throwable {
        System.out.println(jp + ", enclosed by " + enclosingStaticPart);
        return jp.proceed();
      }
    
      @Around("set(@Monitor * *)")
      public Object actionOnSet(ProceedingJoinPoint jp, EnclosingStaticPart enclosingStaticPart) throws Throwable {
        System.out.println(jp + ", enclosed by " + enclosingStaticPart);
        return jp.proceed();
      }
    }
    

    When running the program, the console log says:

    set(int Point.x), enclosed by execution(void Point.setX(int))
    get(int Point.x), enclosed by execution(int Point.getX())
    11
    set(int Point.x), enclosed by execution(void Point.main(String[]))
    get(int Point.x), enclosed by execution(void Point.main(String[]))
    22