Community
Participate
Working Groups
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
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.
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.
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
needs sorting out for RC1.
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.
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.
closing.
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?
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.