Community
Participate
Working Groups
I would like to restrict the usage of a particular method annotation only to types that are marked with a specific annotation. More specifically, I have the method annotations @Read and @Write, and one type annotation called @Access. I want it to be an error when @Read and @Write appear on a method inside a type that is not marked with @Access. I encounter a problem when the methods marked with @Read or @Write are inside a type marked with @Access, but are declared inside an interface that is not marked with @Access. Here is an example : public aspect AccessRestrictedAspect { declare error : execution(@Read public * !@Access *.*(..)) : "Cannot have public @Read methods inside non @AccessClassified types." } public Interface TestInterface { public String getName(); } @Access public class Test1 { @Read public String getName() { return null; } <--- ok } public class Test2 { @Read public String getName() { return null; } <--- gives an error, and should } @Access public class Test2 implements TestInterface { //Note the "implements" @Read public String getName() { return null; } <-- gives an error,but shouldn't }
You might try declare error : !within(@Access *) && execution(@Read public * *(..)) : "no read outside @Access types"; That works for your code below, and I think tracks your meaning better. It does permit non-anonymous nested classes the privileges accorded to @Access types - not sure if that's what you meant. Your code does look like a bug, but it's not a simple issue. I suspect there are a number of semantics issues with annotations not being inherited and method signatures, and ambiguous or inherited method signatures (here from both TestInterface and Test2-3). AspectJ matches execution against all the relevant method signatures (e.g., including supertype), but it's not clear to me that it should match the union of signatures or should match all signatures. For example, if it looks like TestInterface.getName() matches but does not have @Access (on TestInterface), should it look to the Test3.getName() signature which does match? If this is a negation (i.e., look for *executions* which don't match), then should a *signature* that doesn't match cause the error? I don't think so, but then .... So clearly I haven't thought this through enough to help. Anyway, I hope using within(..) works for you while we sort out this bug and any semantics issues. Some working code: ------------------------------- package stuff; @interface Read { } @interface Write { } @interface Access { } class AccessRestrictedAspect { static aspect A { declare error : !within(@Access *) && execution(@Read public * *(..)) : "no read outside access"; } public interface TestInterface { @Read public String getName(); } @Access public class Test1 { @Read public String getName() { return null; } // <--- ok class T { @Read public String getName() { return null; } // <--- ok } } public class Test2 { @Read public String getName() { return null; } // <--- gives an error, and should } @Access public class Test3 implements TestInterface { // Note the "implements" @Read public String getName() { return null; } // no error - no bug here } }
No response, so I presume my response was acceptable. There are still semantics issues here to resolve or document, so I'm making this a doc bug.