Community
Participate
Working Groups
Static inner classes and aspects are permitted to call private static methods in the enclosing class. In the case of aspects this should apply to both methods and advice. However while the following testcase will compile it fails to run: package bug_nnnn; public class InnerAspectCallsPrivateMethod { public void test () { foo("test"); } private static void foo (String from) { System.out.println("? foo() " + from); } public static void main(String[] args) { new InnerAspectCallsPrivateMethod().test(); } private static aspect Aspect { public Aspect () { foo("Aspect.<init>"); } pointcut execTest () : execution(* InnerAspectCallsPrivateMethod.test()); before () : execTest () { foo("before"); } void around () : execTest () { foo("around"); } } } java.lang.NoSuchMethodError: bug_nnnn.InnerAspectCallsPrivateMethod$Aspect.foo (Ljava/lang/String;)V ? foo() Aspect.<init> ? foo() before at bug_nnnn.InnerAspectCallsPrivateMethod$Aspect.ajc$inlineAccessMethod$bug_nnnn_I nnerAspectCallsPrivateMethod$Aspect$bug_nnnn_InnerAspectCallsPrivateMethod$Aspe ct$foo(InnerAspectCallsPrivateMethod.java) at bug_nnnn.InnerAspectCallsPrivateMethod.test_aroundBody1$advice (InnerAspectCallsPrivateMethod.java:43) at bug_nnnn.InnerAspectCallsPrivateMethod.test (InnerAspectCallsPrivateMethod.java) at bug_nnnn.InnerAspectCallsPrivateMethod.main (InnerAspectCallsPrivateMethod.java:26) Exception in thread "main"
The interesting bit of AJ source relating to this bug is in: AccessForInlineVisitor.getAccessibleMethod() which is called with a binding of 'void foo(java.lang.String)' and a receiver Type of 'Aspect'. See comments relating to this bug, prefixed 'Andy' below: { if (!binding.isValidBinding()) return binding; makePublic(receiverType); //??? if (isPublic(binding)) return binding; if (binding instanceof InterTypeMethodBinding) return binding; if (binding.isPrivate() && binding.declaringClass != inAspect.binding) { // Andy: This is where we end up in the case where foo() is a private // Andy: method. We raise its visibility. binding.modifiers = AstUtil.makePackageVisible(binding.modifiers); } // Andy: We then create a ResolvedMember in the *aspect* for the foo method // Andy: which never has its body generated (called something like // Andy: PrivateCall$Aspect.foo() - where PrivateCall is the name of the // Andy: class containing foo(). ResolvedMember m = EclipseFactory.makeResolvedMember(binding, receiverType); if (inAspect.accessForInline.containsKey(m)) return (MethodBinding)inAspect.accessForInline.get(m); // Andy: Now we generate an inline accessor method that calls foo() and // Andy: we use it in the advice. Of course this method will be generated // Andy: but its body will call the method PrivateCall$Aspect.foo() which is // Andy: never generated. MethodBinding ret = world.makeMethodBinding( AjcMemberMaker.inlineAccessMethodForMethod(inAspect.typeX, m)); inAspect.accessForInline.put(m, ret); return ret; } The solution is to raise the visibility and just return the newly accessible method binding as it will then be completely visible to the advice (there is no need for an accessor method). I'm thinking there are a whole bunch of related tests that could be written in this area and currently puzzling through which are likely to break with the change above. Question for Matthew: Do we think it is allowed for around advice in the inner aspect to call a private method foo() in the enclosing class and yet have that around advice affect something in a completely different type? In this case the inlining may cause my change to break (but I suspect we are already broken so I haven't made it worse...)
Ok. I fixed it properly and have covered all cases with tests - even the case when you inline the around advice into an entirely different type. Waiting for build before closing
Fix available: BUILD COMPLETE - build.340 Date of build: 08/14/2004 10:57:39 Time to build: 92 minutes 0 seconds Last changed: 08/14/2004 09:08:57 Latest good AspectJ jar available at: download.eclipse.org/technology/ajdt/dev/aspectj-DEVELOPMENT.jar
Fix released as part of AspectJ 1.2.1