Bug 92048 - matching annotation on method params doesn't work with type parameters
Summary: matching annotation on method params doesn't work with type parameters
Status: RESOLVED FIXED
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.5.0M2   Edit
Hardware: PC Linux
: P3 normal (vote)
Target Milestone: 1.5.0 M3   Edit
Assignee: Adrian Colyer CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-04-20 06:05 EDT by Michal Stochmialek CLA
Modified: 2005-08-19 15:47 EDT (History)
0 users

See Also:


Attachments
extracted test case (477 bytes, text/plain)
2005-04-20 06:06 EDT, Michal Stochmialek CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Michal Stochmialek CLA 2005-04-20 06:05:09 EDT
I have a problem with matching annotations declared on method
parameters, when method uses generics.

Here's extracted 'testcase' (i will also attach it):
-----------------------------------------------
import java.lang.annotation.*;
import java.util.*;

@Target(ElementType.TYPE)
@interface Ann {}

@Ann
class AClass {}

public class Test2 {
        void abc(AClass y) {}
        <T> void par(T y) {}

        public static void main(String[] args) {
                Test2 test = new Test2();
                test.abc(new AClass());
                test.par(new AClass());

                Set set = new HashSet();
                set.add(new AClass());
        }
}


aspect Annotations {
        before() : call(* *(@Ann *)) {
                System.out.println("Before: " + thisJoinPoint);
        }
}
----------------------------------------------

The result of the test on Java5 (JRockit) and AspectJ 1.5.0M2
is folowing:
----------------------------------------------
Before: call(void Test2.abc(AClass))
----------------------------------------------


Initially problem appeared when I tried matching on java.util
collections' methods (see call to Set.add()), but the problem
is the same for simple parametrized method (call to Test2.par()).
Comment 1 Michal Stochmialek CLA 2005-04-20 06:06:39 EDT
Created attachment 20113 [details]
extracted test case
Comment 2 Andrew Clement CLA 2005-04-20 06:07:17 EDT
generics has known problems in M2, will fix for M3.
Comment 3 Andrew Clement CLA 2005-05-10 11:47:11 EDT
First thing, if you are going to match on annotations then you must specify they
have runtime retention - you need to change the definition of Ann to this:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Ann {}

we should be putting out an error message if the annotation is missing runtime
retention but currently we aren't (this a bug I am aware of).

call() matches on the declared signature of a method - in the face of generics
on the bounds of any type parameters.  The declaration of par does not say it
takes an AClass as a parameter, it takes a T and with no bounds specified the
default is Object so it effectively reads 'void par(Object y)' which doesn't
match the pointcut.

This, however, will match:
  
  call(* *(*)) && @args(Ann)

since @args uses runtime type information rather than the static signature and
at runtime the object passed to the call is annotated by @Ann so we get a match.

An interesting case is this method that we could add:

<T extends AClass> void xyz(T y) {}

which again specifys a parameterized method but upper bound is AClass - this
reads like 'void xyz(AClass y)' and does match the variant of the pointcut I
showed above.

All this works in the currently available AspectJ.
Comment 4 Adrian Colyer CLA 2005-08-19 15:47:54 EDT
fixed in May as per Andy's last comment....

Runtime retention is needed when matching with @args (which also allows binding), but not needed when 
you simple use an annotation as part of the signature matching in eg. call or execution.