Reputation: 41
I setup LTW with AspectJ and spring pretty quick and successfull. Here is the setup: beans.xml:
<context:annotation-config />
<aop:aspectj-autoproxy />
<context:spring-configured />
<context:load-time-weaver />
<context:component-scan base-package="com.test.service" />
My service that will be autowired to a class:
@Service
public class MyService {
}
Parent class:
public class Bar {
}
The configurable class, that autowires the service and extends Bar.
@Configurable
public class BarExtended extends Bar{
@Autowired
private MyService service;
public MyService getWeavedInObject(){
return service;
}
}
And just a class that has got a referance to the parent class Bar:
public class Foo {
private Bar bar;
public void setBar(Bar bar) {
this.bar = bar;
}
}
And a successfull test case. It just creates a instance of BarExtended and checks if the LTW worked. The Foo class does nothing.
@Test
public void simple(){
Foo foo = new Foo();
BarExtended barExtended = new BarExtended();
assertNotNull("LTW didn't work.", barExtended.getWeavedInObject());
}
This test runs green. BUT following test failes:
@Test
public void simple(){
Foo foo = new Foo();
BarExtended barExtended = new BarExtended();
foo.setBar(barExtended);
assertNotNull("LTW didn't work.", barExtended.getWeavedInObject());
}
I just insert the line where the class BarExtended is set to Foo. The downcast make the AspjectJ not working.
BTW, when I change the Foo class to use the BarExtended class (so no upcasting is needed):
public class Foo {
private BarExtended bar;
public void setBar(BarExtended bar) {
this.bar = bar;
}
}
The above test will work. Does anyone has an idea why AspjectJ behaves so strange, when a configurable object is upcasted?
Edit: Follwing fails as well:
@Test
public void simple() {
Foo foo = new Foo();
BarExtended barExtended = new BarExtended();
Bar bar = (Bar) new BarExtended();
foo.setBar(bar);
assertNotNull("LTW didn't work.", barExtended.getWeavedInObject());
}
A different BarExtended object is set to Foo and the first barExtended object is ignored by AspectJ. BUT using reflection to instantiate BarExtended works:
@Test
public void simple() throws InstantiationException, IllegalAccessException{
Foo foo = new Foo();
Bar barExtended = (Bar) BarExtended.class.newInstance();
foo.setBar(barExtended);
assertNotNull("LTW didn't work.", ((BarExtended)barExtended).getWeavedInObject());
}
Strange, isn't it?
Thanks a lot
Regards,
Andreas
Upvotes: 2
Views: 860
Reputation: 11
I experience the same problem in a JUnit setup, with the standard spring-instrument setup. When running the same code in a WebSphere container with WebSphereLoadTimeWeaver no problem what so ever!
My openJPA code is enhanced build time. My @Configurable and some other aspects are done load time.
My best guess is that the enhancement of the openjpa inheritance strategy conflicts later on with the LTW and hence giving me some null pointer issues in combination with @Configuarable.
JUNIT EXAMPLE
AbstactWhatEver x = new Concrete(); // @Configurable is working
AbstactWhatEver x = new Concrete(); x.callAnyMethod(); // gives LTW issue on openjpa abstract hence @Configurable is not working
BOTH ABOVE EXAMPLES WORK IN WEBSPHERE ENV.
Did you ever resolve this issue?
Upvotes: 1
Reputation: 62632
I have had trouble in the past where I thought LTW was configured but it was not for reasons that I am not quite sure about. So I am now 100% explicit in my configuration make the following changes to your config file and see if it all works.
<context:load-time-weaver aspectj-weaving="on" />
remove <aop:aspectj-autoproxy />
from your configuration you don't need it you have LTW really running.
When you run your JUnit testing are you passing in the vm argument to tell JUnit where the LTW agent is? If not then you don't have LTW running.
Here is what the docs say about <context:load-time-weaver />
Activates a Spring LoadTimeWeaver for this application context, available as a bean with the name "loadTimeWeaver". Any bean that implements the LoadTimeWeaverAware interface will then receive the LoadTimeWeaver reference automatically; for example, Spring's JPA bootstrap support. The default weaver is determined automatically. As of Spring 2.5: detecting Sun's GlassFish, Oracle's OC4J, Spring's VM agent and any ClassLoader supported by Spring's ReflectiveLoadTimeWeaver (for example, the TomcatInstrumentableClassLoader). The activation of AspectJ load-time weaving is specified via a simple flag (the 'aspectj-weaving' attribute), with the AspectJ class transformer registered through Spring's LoadTimeWeaver. AspectJ weaving will be activated by default if a "META-INF/aop.xml" resource is present in the classpath. This also activates the current application context for applying dependency injection to non-managed classes that are instantiated outside of the Spring bean factory (typically classes annotated with the @Configurable annotation). This will only happen if the AnnotationBeanConfigurerAspect is on the classpath (i.e. spring-aspects.jar), effectively activating "spring-configured" by default. See Javadoc for org.springframework.context.annotation.EnableLoadTimeWeaving for information on code-based alternatives to bootstrapping load-time weaving support.
So in summary putting <context:load-time-weaver />
seems to be really about defining a bean with an id of loadTimeWeaver and scanning the class path looking for special files like aop.xml to determine if aspectJ should be turned on. To make sure that aspectJ is turned on for sure you really need to set aspectj-weaving="on"
that way if it can't turn on aspectJ for whatever reason it will fail on startup which is exactly what you want. In my web app I have a test that I run on web app startup to make sure that aspectJ is running and if it is not it complains.
Upvotes: 1