Bug 158629 - binary-weaving method annotation into a class is working incorrectly
Summary: binary-weaving method annotation into a class is working incorrectly
Status: NEW
Alias: None
Product: AspectJ
Classification: Tools
Component: LTWeaving (show other bugs)
Version: 1.5.2   Edit
Hardware: All Windows XP
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: aspectj inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-09-25 14:28 EDT by Monal CLA
Modified: 2006-09-26 17:12 EDT (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Monal CLA 2006-09-25 14:28:49 EDT
Hi,

Environment:
AspectJ 1.5.2, AspectJ Eclipse Plugin 1.4, Eclipse 3.2, Sun JDK 1.5

Note: I tried both LTW and CTW but ran into the same issue.

I added the before() advice to MyTestAspect (lines 7 - 9) with
junit.jar on the classpath. I added a call to the InheritAnnot method
to call junit.framework.TestCase setUp method (super.setUp). Now line
8 executes and the message displayed. Previously I was using
reflection (see InheritAnnot class below) to verify that the
annotation was applied to the TestCase.setUp method, and this test
failed in detecting the presence of the annotation.

So, I think the bug is - Introduced annnotation is available when
the method executes but the same annotation information is not
available via reflection using the Method.getAnnotations() call.

Note: MyAnnotaiton has RetentionPolicy.RUNTIME

import junit.framework.TestCase;
1   public aspect MyTestAspect {
2           @MyAnnotation
3           public static void TestCase.testCaseSetUp() {
4           }
5           // declare @method : * TestCase.testCaseSetUp() : @MyAnnotation;
6           declare @method : * TestCase.setUp() : @MyAnnotation;
7           before() : execution(@MyAnnotation * TestCase.setUp()) {
8                   System.err.println(" ** setup here: " + thisJoinPoint);
9           }
10   }


// Aspect verification class
public class InheritAnnot extends TestCase {
      public InheritAnnot() {
          super.setUp(); // try catch surrounding this ommitted
      }
      public static void main(String[] args) throws Throwable {
              InheritAnnot ia = new InheritAnnot();
              Class curClazz = ia.getClass();
              do {
                     System.out.println("Current Class: " + curClazz.getName());
                     Method[] ms = curClazz.getDeclaredMethods();
                     for(Method m : ms) {
                       if(m.getName().equalsIgnoreCase("testCaseSetUp")) {
                         System.out.println(" -- Method Name: " + m.getName());
                         m.invoke(curClazz, new Object[0]);
                       }
                       Annotation[] mannots = m.getAnnotations();
                       for(Annotation ma : mannots) {
                         System.out.println("@ Found annotation - " + ma
                                   + " in Class: " + curClazz.getName()
                                   + " on method: " + m.getName());
                       }
                     }
              } while((curClazz = curClazz.getSuperclass()) != null);
      }//main
}

Please see the thread http://dev.eclipse.org/mhonarc/lists/aspectj-users/msg06787.html titled "Binary-weaving method annotation into a class in a jar not working - is this a bug?" for the complete discussion

Monal
Comment 1 Andrew Clement CLA 2006-09-26 04:22:52 EDT
I have distilled this to a simple test case:

----8<-----------
public class TestCase {
  public void setUp() {}
}
----8<-----------
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {}
----8<-----------
import java.lang.annotation.*;
import java.lang.reflect.*;

aspect MyTestAspect {
  declare @method : * TestCase.setUp() : @MyAnnotation;
}

public class ApplyAnnotation {
  public static void main(String[] args) throws Throwable {
    Class curClazz = TestCase.class;
    Method[] ms = curClazz.getDeclaredMethods();
    for (Method m : ms) {
      Annotation[] mannots = m.getDeclaredAnnotations();
      System.out.println(m);
      for (Annotation ma : mannots) {
        System.out.println(curClazz.getName()+"."+m.getName()+"() has annotation "+ma);
      }
    }
  }
}
----8<-----------

and these steps:

F:\pr158629>ajc TestCase.java -d output1

F:\pr158629>ajc -inpath output1 MyAnnotation.java ApplyAnnotation.java -d output2 -1.5


F:\pr158629>cd output2

F:\pr158629\output2>java ApplyAnnotation
public void TestCase.setUp()


the annotation is not shown.

The reason?  TestCase is not a java5 class - that first compilation step did not build TestCase as a java5 class so the reflection API will not find any annotations put into it.  I imagine it is the same with junit - it is not Java5, so does not support inclusion of annotations.  If you add the junit source to the project, of course it will work (everything built at java5).

i think this is working as designed - we don't currently support 'promotion' of a class to Java5 because it gets a Java5 features added to it.  This situation needs a warning at least, and maybe we do decide to do the auto-promotion, but that needs thinking through.
Comment 2 Monal CLA 2006-09-26 12:19:38 EDT
(In reply to comment #1)

The before advice however recognizes that the setUp method is annotated and prints the message. I imagine AspectJ sees that the class version is pre JDK 5, so it does not weave the annotation into the class. If so, then where is the annotation being stored for the before advice to match the joinpoint @MyAnnotation * TestCase.setUp()?

7  before() : execution(@MyAnnotation * TestCase.setUp()) {
8      System.err.println(" ** setUp here: " + thisJoinPoint);
9  }

Monal Daxini
Comment 3 Andrew Clement CLA 2006-09-26 16:48:12 EDT
> The before advice however recognizes that the setUp method is annotated and
> prints the message. 

Yep - the matching doesn't currently worry about the version of the file.

> I imagine AspectJ sees that the class version is pre JDK 5, so it 
> does not weave the annotation into the class. 

No - AspectJ does weave the file and include the annotation.  javap'ing the output will show that the .class file includes the annotation.  It is simply ignored when the class is loaded and the reflection API is used - it sees a pre Java5 class and makes the (valid) assumption that it can have no annotations.

> If so, then where is the annotation being stored for the before advice to
> match the joinpoint

It is stored in the class file as I mentioned in the previous comment.

The question is whether we should make this an ERROR - to try and annotate a type of the wrong level.  Or think about auto-promoting the class level to Java5 - but that will involve working through more use cases - would we promote just that one, or all of them, would we support a -target option like javac or just guess that output level matches selected input level (-1.3, -1.4, -1.5)


Do you need the annotation to be found via reflection?  Or do you just need the advice to match?
Comment 4 Ron Bodkin CLA 2006-09-26 16:52:59 EDT
I think it would be unfortunate to either make this an error or to auto-promote the class file. There are users who are using tools like the JSR-175 backport to put annotation attributes in Java classes that are not targeting a Java 1.5 VM. E.g., http://blogs.codehaus.org/people/avasseur/archives/001121_aspectj_aspect_and_java_13.html

It is useful to be able to use these annotations in AspectJ with Java < 1.5, so I think it would be better to make this an Xlint option that defaults to be a warning (Xlint so those using the feature could turn it off).

I think this is really a request for enhancement for the Java VM to recognize annotations in pre Java-5 bytecode.
Comment 5 Andrew Clement CLA 2006-09-26 16:55:00 EDT
How unusual, Ron wants an xlint that can be turned off :D
Comment 6 Ron Bodkin CLA 2006-09-26 16:59:11 EDT
Just a thought...
Comment 7 Monal CLA 2006-09-26 17:12:44 EDT
(In reply to comment #3)

> Do you need the annotation to be found via reflection?  Or do you just need the
> advice to match?
Third party library I am using needs the annotation to be found via reflection.
But for now, I have a couple of work arounds - not elegant but will work for
now.

Monal Daxini