Community
Participate
Working Groups
AspectJ version 1.1B2 Mandrake Linux 9.0 Sun JDK 1.3.1_01 and 1.4.1_01 The code below works with aspectj 1.0.6. If "execution" in the pointcut is replaced with "call" the example executes as normal. When run, an exception reported: java.lang.ExceptionInInitializerError and cause is NullPointerException as follows: > Exception in thread "main" java.lang.ExceptionInInitializerError > at au.com.blackcat.client.Client.<init>(Client.java:3) > at au.com.blackcat.client.Client.main(Client.java:8) > Caused by: java.lang.NullPointerException > at au.com.blackcat.client.Watchcall.<init>(Watchcall.java:3) > at au.com.blackcat.client.Watchcall.ajc$clinit(Watchcall.java) > at au.com.blackcat.client.Watchcall.<clinit>(Watchcall.java:3) > ... 2 more compiled using > ajc @files.lst where files.lst contains > src/au/com/blackcat/client/Client.java > src/au/com/blackcat/client/Watchcall.java environment var CLASSPATH is > /opt/aspectj1.1/lib/aspectjtools.jar:/opt/aspectj1.1/lib/aspectjrt.jar Run with: > java -cp . au.com.blackcat.client.Client Client.java: > package au.com.blackcat.client; > > public class Client > { > > public static void main(String[] args) > { > Client c = new Client(); > } > > } Watchcall.java: > package au.com.blackcat.client; > > public aspect Watchcall { > > pointcut myConstructor(): execution(new(..)); > > before(): myConstructor() { > System.err.println("Entering Constructor"); > } > }
This is actually the correct behavior masked by throwing a very badly chosen Exception. In the current CVS compiler, this has now been changed to throw org.aspectj.lang.NoAspectBoundException I've also written an extensive usage note on the problem which will appear in README-11.html in the next release, using your test proggram. Here's what it says: In AspectJ 1.0.6, we made an effort to hide some complications with Aspect instantiation from the user. In particular, the following code compiled and ran: public class Client { public static void main(String[] args) { Client c = new Client(); } } aspect Watchcall { pointcut myConstructor(): execution(new(..)); before(): myConstructor() { System.err.println("Entering Constructor"); } } But there's a conceptual problem with this code: The before advice should run before the execution of all constructors in the system. It must run in the context of an instance of the Watchcall aspect. The only way to get such an instance is to have Watchcall's default constructor execute. But before that executes, we need to run the before advice... AspectJ 1.0.6 hid this circularity through the ad-hoc mechanism of preventing an aspect's advice from matching join points that were within the aspect's definition, and occurred before the aspect was initialized. But even in AspectJ 1.0.6, this circularity could be exposed: public class Client { public static int foo() { return 3; } public static void main(String[] args) { Client c = new Client(); } } aspect Watchcall { int i = Client.foo(); pointcut myConstructor(): execution(new(..)) || execution(int foo()); before(): myConstructor() { System.err.println("Entering Constructor"); } } This program would throw a NullPointerException when run, since Client.foo() was called before the Watchcall instance could be instantiated. In AspectJ 1.1, we have decided that half-hiding the problem just leads to trouble, and so we are no longer silently hiding some join points before aspect initialization. However, we have provided a better exception than a NullPointerException for this case. In AspectJ 1.1, both of the above programs will throw org.aspectj.lang.NoAspectBoundException.