Bug 167775 - Annotation pointcut fails with supertype reference
Summary: Annotation pointcut fails with supertype reference
Status: RESOLVED INVALID
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.5.3RC1   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 1.6.1   Edit
Assignee: aspectj inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-12-12 20:39 EST by Karl Schaefer CLA
Modified: 2008-06-11 17:28 EDT (History)
1 user (show)

See Also:


Attachments
Annotation based aspect. (180 bytes, text/plain)
2006-12-12 20:40 EST, Karl Schaefer CLA
no flags Details
The sample annotation. (295 bytes, text/plain)
2006-12-12 20:40 EST, Karl Schaefer CLA
no flags Details
A simple class. (101 bytes, text/plain)
2006-12-12 20:40 EST, Karl Schaefer CLA
no flags Details
Baz' subclass. (136 bytes, text/plain)
2006-12-12 20:42 EST, Karl Schaefer CLA
no flags Details
Example test demonstrating the reference problem (291 bytes, text/plain)
2006-12-12 20:43 EST, Karl Schaefer CLA
no flags Details
Complete Test Case (1.15 KB, text/plain)
2006-12-12 23:46 EST, Karl Schaefer CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Karl Schaefer CLA 2006-12-12 20:39:22 EST
If you create an object that is a subclass of interface implementation and reference it via the superclass or interface the compiler does not recognize the poincut on the child/implementation.

In the attachment set:
Foo is the aspect that defines a pointcut on the annotation Bar.
Bar is a method-based annotation.
Baz is a simple class.
ChildOfBaz extends Baz, overriding Baz' only method execute and annotating it with Bar.
Test runs some execute methods.

Test produces the following output:
In Baz.
In ChildOfBaz
call(void ChildOfBaz.execute())
In ChildOfBaz
Comment 1 Karl Schaefer CLA 2006-12-12 20:40:11 EST
Created attachment 55543 [details]
Annotation based aspect.
Comment 2 Karl Schaefer CLA 2006-12-12 20:40:28 EST
Created attachment 55544 [details]
The sample annotation.
Comment 3 Karl Schaefer CLA 2006-12-12 20:40:50 EST
Created attachment 55545 [details]
A simple class.
Comment 4 Karl Schaefer CLA 2006-12-12 20:42:03 EST
Created attachment 55546 [details]
Baz' subclass.
Comment 5 Karl Schaefer CLA 2006-12-12 20:43:50 EST
Created attachment 55547 [details]
Example test demonstrating the reference problem
Comment 6 Karl Schaefer CLA 2006-12-12 23:46:14 EST
Created attachment 55561 [details]
Complete Test Case
Comment 7 Karl Schaefer CLA 2006-12-12 23:47:43 EST
Created an all-in-one test case and added some better output.  Test case now returns:

false
Baz
true
ChildOfBaz
call(void ChildOfBaz.execute())
true
ChildOfBaz
Comment 8 Andrew Clement CLA 2006-12-13 03:29:03 EST
the program is working as designed.  In your example the 'baz' variable is of type 'Baz'.  The pointcut is matching based on the static type information available at the call join points.  You make 3 calls to execute - only at the last one, after the cast, do we statically know that you are calling execute on the subclass, hence it matches.  Your second call to execute is identified as a call to Baz.execute() because that is the type of the variable 'baz'.  I know the subclass implementation runs because the runtime type held in baz is ChildOfBaz, but at compile time we don't know that and it isn't used in the matching process.
Comment 9 Karl Schaefer CLA 2006-12-13 08:24:29 EST
OK.  Expected for you, not for me.  I guess I had some faulty assumptions about how the compiling was done.

Here's the problem perhaps you can provide a solution.  I have a Command interface with an execute method.  I have many commands that implement this interface and I have an annotation for security checks.  I want to not have to annotate the interface execute method since some commands should just work, and even if I wanted to, I'm having difficulty imagining the correct "generic" annotation.  However, I typically pass these back and forth as Command instances, so how do I get this to work as I expected it to (ie supertype references still allow subtype annotation pointcuts to work)?
Comment 10 Andrew Clement CLA 2008-06-11 17:28:37 EDT
Better late than never....

If you want to match based on runtime information, then you need to use a runtime matching pointcut, like @annotation().  Here is a sample program where the @Secured execute method is checked.

import java.lang.annotation.*;

public class Secure {
  public static void main(String []argv) {
    new SecureCommand().execute();
    new NormalCommand().execute();
  }
}


interface ICommand {
  void execute();
}


class SecureCommand implements ICommand {
  @Secured
  public void execute() {System.out.println("Secure command running"); }
}

class NormalCommand implements ICommand {
  public void execute() {System.out.println("Normal command running"); }
}

@Retention(RetentionPolicy.RUNTIME)
@interface Secured {}

aspect X {
  before(): execution(* ICommand.execute(..)) && @annotation(Secured) {
    System.out.println("Running security check");
  }
}

However, i'm not sure how that would work in the face of your super calls...  I doubt you still care after all this time, but I thought I'd comment before I close it :)  Let me know if you still want to discuss by reopening this.