Bug 114005 - annotated ITD fields on interfaces have no annotation
Summary: annotated ITD fields on interfaces have no annotation
Status: RESOLVED FIXED
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.5.0M4   Edit
Hardware: PC Windows XP
: P2 normal (vote)
Target Milestone: 1.5.0RC1   Edit
Assignee: Adrian Colyer CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-10-27 13:23 EDT by Vincenz Braun CLA
Modified: 2005-11-09 09:47 EST (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Vincenz Braun CLA 2005-10-27 13:23:19 EDT
As stated in the notebook it is allowed to annotate field ITDs.
This seems not to work properly with interfaces.


public interface TestInterface {

}

@Retention(RetentionPolicy.RUNTIME)
public @interface SampleAnnotation {

}

public aspect Declaration {

	declare parents: (@SampleAnnotation *) implements TestInterface;
	
        // this is fine
	@SampleAnnotation 
	public transient String Test.firstProperty;
	
        / this does not work
	@SampleAnnotation
	public transient String TestInterface.secondProperty;
	
        // this also does not work
	declare @field: * TestInterface+.*: @SampleAnnotation;
}

secondProperty has no Annotation as one can see with:


public class Test implements TestInterface {

	public static void main(String[] args) {
		for (Field field: Test.class.getFields()) {
			System.err.println(field.toString().concat(" ").concat
(String.valueOf(field.isAnnotationPresent(SampleAnnotation.class))));
		}
	}
}

I did not try whether this is also the case for method ITS on interfaces.
Secondly the field name is 
ajc$interField$test_Declaration$test_TestInterface$secondProperty instead of
simply secondProperty. Is this what is meant with bug 73507?

What is with private and package protected ITD of fields and runtime 
reflection? Because the field name is mangled (Test.class.getField
("firstProperty") raises a NoSuchFieldException when declared private or 
package protected). Also "declare @field: * Test+.*: @SampleAnnotation;" is 
not applied for private or package protected declarations. So should one only
annotate public field IDTs (supported by compiler warnings) to have useful 
runtime behaviour (with runtime RetentionPolicy annotations)?

So it is strange that the introductory example on annotations shows annotated 
private field ITDs on interfaces :-)

Thank you very much for your help,
Vincenz
Comment 1 Andrew Clement CLA 2005-10-27 14:00:17 EDT
Have you tried pointcut matching to see if that recognizes that certain elements
have annotations, rather than poking around in the bytecode?

We fixed a bug a while ago about copying the annotations specified on ITDs onto
the public members (bug 98901), I thought that covered the ITD on interface case
but possibly not.

Yes, bug 73507 is to do with creating mangled member names for public fields.

For non public fields, the members introduced on the target type are mangled to
preserve the visibility rules.  You specify the field is 'private' to the aspect
so no-one outside the aspect should be able to see it - we can't put a private
field with the unmangled name on the target as then the methods in the target
could see it.  Similar story with package protected.
Comment 2 Andrew Clement CLA 2005-10-27 14:27:51 EDT
This works as expected:

====
import java.lang.annotation.*;

@interface Annotation {}


class C implements I {
}

interface I {
}

aspect X {

  public static void main(String[] argv) {
    C c = new C();
    System.err.println(c.i);
  }

  @Annotation
  public int I.i;

  before(): get(@Annotation * *) {
  }

}
====

i.e. pointcut matching works for ITD'd fields.  Here is the output with
-showWeaveInfo:

C:\>ajc -1.5 -showWeaveInfo A.java
Join point 'field-get(int I.i)' in Type 'X' (A.java:16) advised by before adv
ice from 'X' (A.java:22)

Type 'I' (A.java) has intertyped field from 'X' (A.java:'int I.i')

Type 'C' (A.java) has intertyped field from 'X' (A.java:'int I.i')

===
So the developers notebook isn't incorrect - it doesn't say you'll find the
annotations on the members introduced into the types, it is the ITD that is
annotated.

However, under that other bug we tried to allow for the case of public ITDs as
its possible you may be running other tools off the output and need them to be
annotated.  So to be complete we should copy them across in the case you raised
here.
Comment 3 Vincenz Braun CLA 2005-10-27 17:08:32 EDT
Thanks to both of you for your quick replies. I should marked this
as a request for clarification. I am confused about the semantics of
an annotated ITD. I see two distinct possibilities:

1. Only the ITD is annotated. No copy semantic. No matching
of get(@Annotation * *) as in aspect X of your example. To annotate
declared members one would have to use declare @method @field etc. or
annotate the annotation with e.g. a @Copy (makes (@Annotation * *) matching).
With runtime retention policy these annotations would be present in the 
aspects bytecode annotating only the ITD. 
The annotations would be of no use for types that have declarations. 
Is there a use for only annotating the ITD?


2. The semantic states: declare an annotated inter type field or method etc. 
With runtime retention policy the annotation is copied to the declared members
in the type regardless off scope. Matching of get(@Annotation * *) as in 
aspect X of your example. One would not have to use declare @method or @field 
for the declaration. The annotation is present when using reflection.

The current implementation seems to be a mixture and in my opinion makes some 
problems:

1. the semantic is not clear (either use @Copy or declar @field, @method etc.)
   -- at least for me at the moment :-)
2. annotations should be present regardless of scope
3. even annotations of public field ITD to interfaces are not present at 
   runtime via reflection. 
   Do the 29 use cases of 98901 cover public ITD field declarations on 
   interfaces?

Especially point 3 is important.

Here is a use case. I have a EJB3 @Entity with FIELD AccessType. Making
a entity bean a bound bean like in the bean example I declared a private 
PropertyChangeSupport in an aspect. 
I would like to annotate this declared field with
@Transient so it gets not persisted. (Declaring it transient would be
sufficient in this use case. But Hibernate has a bug depending on using 
annotation with @Transient.) There may be other tools using reflection and 
annotations to filter important members. And other use cases where it makes
sense to copy annotations regardless of scope.


Thank you very much for your patience,
Vincenz
Comment 4 Andrew Clement CLA 2005-10-28 10:08:33 EDT
needs sorting out for RC1.
Comment 5 Andrew Clement CLA 2005-11-08 07:12:35 EST
Right - I have addressed the bug described in point (3) in the above comment:


> 3. even annotations of public field ITD to interfaces are not present at 
>    runtime via reflection. 
>    Do the 29 use cases of 98901 cover public ITD field declarations on 
>    interfaces?

Annotations on public field ITDs that target interfaces are copied to the fields
that are placed in the types implementing the interface.  This was a case not
covered by 98901.  The field name is still mangled, but the annotation is there.

There should be no difference between directly annotating a field

@SomeAnnotation
int I.f;

and using declare @field:

int I.f;
declare @field: int I.f: @SomeAnnotation;

if they behave at all differently, its a bug.

Addressing other points:

> 1. the semantic is not clear (either use @Copy or declar @field, @method etc.)
>    -- at least for me at the moment :-)

The semantic is that for public ITDs the annotations are copied - because some
tool may be driving off them (e.g. hibernate).

> 2. The semantic states: declare an annotated inter type field or method etc. 
> With runtime retention policy the annotation is copied to the declared members
> in the type regardless off scope. Matching of get(@Annotation * *) as in 
> aspect X of your example. One would not have to use declare @method or @field 
> for the declaration. The annotation is present when using reflection.

As I mentioned above, there should be no difference between declaring the
annotation on a member and specifying it directly against the member.
Comment 6 Andrew Clement CLA 2005-11-09 02:48:23 EST
the fixes are available in the latest build.  Does it now go some way towards
addressing your use case?  I'm now looking at whether to mangle public field
ITDs on interfaces in bug 73507.
Comment 7 Andrew Clement CLA 2005-11-09 02:48:58 EST
closing.
Comment 8 Vincenz Braun CLA 2005-11-09 08:00:35 EST
Thank you very much. For me it is important that all
annotations are copied regardless of scope. What are the
reasons to constrain it to public ITDs only?

For me:
@SomeAnnotation
int I.f;
and using declare @field:
int I.f;
declare @field: int I.f: @SomeAnnotation;
behave the same. 

Is this last update also available via Eclipse AJDT Update Site?
Comment 9 Andrew Clement CLA 2005-11-09 09:47:08 EST
Possibly I was hasty in thinking of fields and methods as the same.  You will
find whatever visibility you declare the field ITD on an interface, you will get
a public member in the implementors of the interface that has the annotations.

I only copy the annotations because tools can drive off them at a later time -
my intention is not to make java reflection work where users write programs that
trawl through the ajc$ fields making assumptions about the fields (i.e. someone
notices an ajc$interField$X$I$field1, that must be a field really called
'field1' from aspect 'X' and then to find annotations on it they ask the itd'd
field) - anyone that writes code like that is writing very fragile code since
the implementation could change at any moment (for example if 73507 goes ahead).    

If someone wants to reflect on an AspectJ program, they should use the AspectJ
meta aspect protocol interface which understands all about the constructs - and
if you did ask an ITD field through the MAP for its annotations, it could easily
query the ITD definition in the aspect to retrieve them, it doesnt need them to
exist on the target mangled field inserted into a type.

I dont think this fix will be in AJDT until Monday.