Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [ajdt-dev] annotating shadow methods


> In the end, the original question still stands though; Is there a way to annotate shadow/synthetic methods through AspectJ or do I need to dive into asm myself?

No, I'm afraid you can't do it with AspectJ, they will be ignored by the weaver.  They are synthetic meaning they are there as a by-product of weaving and not really anything for the user to worry about or look at  - similar to forwarding bridge methods for generic type calls.  You will need to add annotations via something like Asm.

cheers,
Andy.

2008/8/6 Wim Depoorter <wim.depoorter@xxxxxxxx>
That's exactly what I have tried.  It works with normal methods, but not with the generated shadow methods of around advice since AspectJ doesn't consider these synthetic methods to be join points as I found out through experimentation and later from http://hugunin.net/papers/aosd-2004-cameraReady.pdf section 4.3 .

Sample code is provided below (is it acceptable to attach source code, btw?). The "declare @method" should work on all methods whose name starts with "aroundTest". As can be seen from the output, there are 3 such methods in the call stack, but only one "calling annotated method".
The "aroundTest_aroundBody..." shadow methods simply are not annotated (compare aroundTest() with aroundTest_aroundBody* in class files). The signature of these methods has a "synthetic" modifier, leading to the observed behaviour (private static final synthetic void aroundTest_aroundBody...(...)).
What surprises me even more is the fact that, from inspecting the bytecode, these shadow methods don't seem to throw MyException, which is actually a checked exception (compare Main with *_aroundBody* in class files)... It is my understanding that checked exceptions need to be caught or passed further up the stack. Nevertheless, everything seems to go well and when actually throwing such an exception it is passed up the stack somehow... Suffice to say I'm not very familiar with all the wizardry going on. I include the Test.class and Main.class file bytecode (as seen from eclipse) for reference.

In the end, the original question still stands though; Is there a way to annotate shadow/synthetic methods through AspectJ or do I need to dive into asm myself?

regards,

Wim


CODE:
==
package aroundAdvice;
public class Test {
  public void aroundTest() throws MyException {
      System.out.println("Test.run()");
      throw new MyException();
  }
}
==
package aroundAdvice;
privileged aspect AroundAdvice {

  void around() throws MyException: call(* *.aroundTest()) {
      System.out.println("before proceed");
      proceed();
      System.out.println("after proceed");
  }
    declare @method : * *.aroundTest*(..) : @MyAnnotation;
//    declare @method :  private static final synthetic void *.aroundTest*(..) : @MyAnnotation; //not valid
//    declare @method :  private static final void Main.aroundTest_*(..) : @MyAnnotation; //doesn't match
    before(): call(@MyAnnotation * *.*(..)) {
      System.out.println("calling annotated method");
  }
}
==
package aroundAdvice;
public class MyException extends Exception {}
==
package aroundAdvice;
public @interface MyAnnotation {}
==
package aroundAdvice;
public class Main {
  public static void main(String[] args) throws MyException {new Test().aroundTest();}
}
==

OUTPUT:
==
before proceed
calling annotated method
Test.run()
Exception in thread "main" aroundAdvice.MyException
  at aroundAdvice.Test.aroundTest(Test.java:6)
  at aroundAdvice.Main.aroundTest_aroundBody0(Main.java:5)
  at aroundAdvice.Main.aroundTest_aroundBody1$advice(Main.java:7)
  at aroundAdvice.Main.main(Main.java:5)
==

BYTECODE:
==
// Compiled from Test.java (version 1.6 : 50.0, super bit)
public class aroundAdvice.Test {

 // Method descriptor #6 ()V
 // Stack: 1, Locals: 1
 public Test();
  0  aload_0 [this]
  1  invokespecial java.lang.Object() [8]
  4  return

 // Method descriptor #6 ()V
 // Stack: 2, Locals: 1
 @aroundAdvice.MyAnnotation
 public void aroundTest() throws aroundAdvice.MyException;
   0  getstatic java.lang.System.out : java.io.PrintStream [19]
   3  ldc <String "Test.run()"> [25]
   5  invokevirtual java.io.PrintStream.println(java.lang.String) : void [27]
   8  new aroundAdvice.MyException [16]
  11  dup
  12  invokespecial aroundAdvice.MyException() [33]
  15  athrow

}
==
// Compiled from Main.java (version 1.6 : 50.0, super bit)
public class aroundAdvice.Main {

 // Method descriptor #6 ()V
 // Stack: 1, Locals: 1
 public Main();
  0  aload_0 [this]
  1  invokespecial java.lang.Object() [8]
  4  return

 // Method descriptor #15 ([Ljava/lang/String;)V
 // Stack: 3, Locals: 2
 public static void main(java.lang.String[] args) throws aroundAdvice.MyException;
   0  new aroundAdvice.Test [20]
   3  dup
   4  invokespecial aroundAdvice.Test() [22]
   7  astore_1
   8  aload_1
   9  invokestatic aroundAdvice.AroundAdvice.aspectOf() : aroundAdvice.AroundAdvice [58]
  12  aconst_null
  13  invokestatic aroundAdvice.Main.aroundTest_aroundBody1$advice(aroundAdvice.Test, aroundAdvice.AroundAdvice, org.aspectj.runtime.internal.AroundClosure) : void [62]
  16  return

 // Method descriptor #32 (LaroundAdvice/Test;)V
 // Stack: 1, Locals: 1
 private static final synthetic void aroundTest_aroundBody0(aroundAdvice.Test arg0);
  0  aload_0
  1  invokevirtual aroundAdvice.Test.aroundTest() : void [23]
  4  return

 // Method descriptor #60 (LaroundAdvice/Test;LaroundAdvice/AroundAdvice;Lorg/aspectj/runtime/internal/AroundClosure;)V
 // Stack: 2, Locals: 4
 private static final synthetic void aroundTest_aroundBody1$advice(aroundAdvice.Test this, aroundAdvice.AroundAdvice ajc_aroundClosure, org.aspectj.runtime.internal.AroundClosure arg2);
   0  getstatic java.lang.System.out : java.io.PrintStream [38]
   3  ldc <String "before proceed"> [40]
   5  invokevirtual java.io.PrintStream.println(java.lang.String) : void [46]
   8  aload_2
   9  astore_3
  10  aload_0 [this]
  11  invokestatic aroundAdvice.Main.aroundTest_aroundBody0(aroundAdvice.Test) : void [64]
  14  getstatic java.lang.System.out : java.io.PrintStream [38]
  17  ldc <String "after proceed"> [54]
  19  invokevirtual java.io.PrintStream.println(java.lang.String) : void [46]
  22  return

}
==

Andrew Eisenberg schreef:

Perhaps declare annotation will suit your needs:

http://www.eclipse.org/aspectj/doc/released/adk15notebook/annotations-declare.html

On Wed, Aug 6, 2008 at 2:46 AM, Wim Depoorter <wim.depoorter@xxxxxxxx> wrote:
 
Hello everyone,

I'm trying to use a new continuation library (Kilim) in combination with
aspects. In order to support continuations (to create light-weight threads)
in Java, this library has its own weaver which I run after aspect weaving
(this order cannot be changed). A requirement of this library is that all
methods in a call stack that calls a method that can suspend are tagged. All
these tagged methods are then instrumented by the Kilim weaver to be able to
store (the state of) the stack on suspend and restart from that point on
resume.

Originally tagging was done with an annotation (@pausable), but the usage of
around advice breaks this paradigm as it is not possible to annotate the
generated <*private static final synthetic void
someMethod_aroundBody0(..)*>* *and <*private static final synthetic void
**someMethod**_aroundBody1$advice(..)*> shadow methods. Since AspectJ also
doesn't consider this to be join points, the annotations cannot be woven in
afterwards as well.

A possible solution to the problem was to tag methods with a checked
exception (throws Pausable) instead of an annotation, but while around
advice allows this, the generated shadow methods do not throw Pausable
themselves, invalidating this approach as well.

At the moment it seems to me that the only thing about the signature of the
generated shadow methods that can be controlled is the name, but it is quite
unrealistic to require a special naming convention for such methods when
there is such a nice system as annotations...
Is there a way to declare annotations on the generated shadow methods
through AspectJ? Is there another way around this problem (without diving
into asm myself)? Or is my best option at this point to start studying asm?

thanks,

Wim Depoorter

_______________________________________________
ajdt-dev mailing list
ajdt-dev@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/ajdt-dev


   
_______________________________________________
ajdt-dev mailing list
ajdt-dev@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/ajdt-dev
 


_______________________________________________
ajdt-dev mailing list
ajdt-dev@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/ajdt-dev



Back to the top