Community
Participate
Working Groups
The PointcutParser interface and the RecflectionWorld on which it depends cannot be used in a run-time environment where the user application and AspectJ are loaded by separate class loaders. This is because the ReflectionWorld uses an unqualified Class.forName() call. The existing RuntimePointcuts testcase passes because the current harness (incorrectly) loads the testcase and AspectJ with the same class loader (see AjcTestCase.run ()). The attached modification to the XML script simulates a more realistic environment. The ReflectionWorld needs to be explicitly created with a class loader. Using Thread.getContextClassLoader() is a traditional solution but problematic for both the test harness and environments like OSGi that do not associate a new thread with each application.
Created attachment 29868 [details] Testcase Using the <run ltw=""> option in the harness ensures the testcase is loaded by a separate class loader.
See also Bug 116755. Starting with a World would at least allow lint warnings to be configured.
I've been all through the reflective world and pointcut parser and made sure that a user supplied classloader can be used in all locations. Construct a ReflectionWorld using a classloader, or call setClassLoader on a PointcutParser and all should be well. I've applied the test case patch and the updated test passes with this change in place. I also had to change the test in BcelWorld to determine if an aspect is an @AspectJ aspect - it is not sufficient simply to look for the @Aspect annotation since code style aspects have that too. I now do the additional work to make sure that code style aspects compiled with 1.5 don't return true. Will close report once fix is available in a published build.
Fix now available in published build.
This interface fails to resolve annotions. Working on a patch for bug 117885, which ensures AspectJ and a testcase are not loaded by the same class loader, the ReflectOnAjcCompiledPointcuts test failes because "MyAnn" cannot be loaded. The problem is Java15ReflectionBasedReferenceTypeDelegate which uses the default constructor PointcutParser() which does not pass on its ReflectionWorld. Fortunately this is the only place. As I said in our discussion the PointcutParser() constructor makes no sense. Its existence will be a source of hard to solve bugs. It should be withdrawn in favour of a factory method on RelflectionWorld or some facade class.
You can tell I don't like the PoincutParser() default constructor can't you. My primary concern is that an API shouldn't allow a user to get into trouble. A program using this API will run just fine in a simple test environment then fail later in a more complex one (read difficult to diagnose problems) with an IllegalArgumentException which does not say "you need to supply a class loader matey" to me. Worse still you throw away the stack trace from the original ReflectionWorldException (because you can't nest exceptions in JDK 1.3) which gave some hint as to the actual problem. The PointcutParser() does type resolution which is not clear from the javadoc. Worse still it does resolution relative to itself not, as the user may assume, relative to the invoking program. By not asking the user for the class loader the API assumes we don't need it, but we do.
I've taken away all of the constructors, and replaced them with static factory methods that allow me to specify a descriptive name. I also had to revert one place where I was using the supplied classloader to load a class when I actually should have been using the weaver-loading classloader - in the ReflectionBasedReferenceTypeDelegateFactory. Fix in tree, waiting on build.
fix now available