Update 5: I've downloaded the latest Spring ToolsSuite IDE based on the latest Eclipse. When I import my project as a Maven project, Eclipse/STS appears to use the Maven goals for building my project. This means AspectJ finally works correctly in Eclipse.
Update 4: I have ended up just using Maven + AspectJ plugin for compile-time weaving, effectively bypassing Eclipse's mechanism.
Update 3: It seems AspectJ's Eclipse plug-in breaks Eclipse's ability to correctly Publish to Tomcat. Only by removing the AspectJ capability on a project can I get it to properly Publish again. Very annoying.
Update 2: I have this now working in Eclipse. It makes me very uncomfortable to say this, but I have no idea how I got it working from either Eclipse or Maven builds. It appears to be a compile issue rather than a run-time issue.
Update 1: It appears I've gotten this to work via Maven builds, but I have no idea how. Eclipse still doesn't work. The only thing I changed in the pom.xml was adding these (insignificant?) configuration parameters:
<source>1.6</source>
<complianceLevel>1.6</complianceLevel>
<verbose>true</verbose>
<showWeaveInfo>true</showWeaveInfo>
<outxml>true</outxml>
I'm actually worried that I have a repeat of this problem, where everything works inconsistently. I will keep this question updated as I learn more.
With regards to Eclipse, I made some progress by taking the binary aspects I wish to weave - in this case spring-aspects.jar - and copying it out of my classpath. I then add this now external jar to my Aspect Path. After doing this, Eclipse properly shows me AspectJ markers in my code. It's annoying that I can't just leave spring-aspects.jar in my Java Build Path which is maintained by Maven for me via the Maven plug-in. For some reason, however, the AspectJ plug-in doesn't see the binary aspects unless they're explicitly added to the Aspect Path.
Original Post: @Configurable is a Spring annotation that allows dependencies to be injected into objects instantiated external to Spring (for example, by Hibernate or some Factory class).
I was using this annotation previously with load-time weaving and it mostly worked. Occasionally I would boot up and nothing would get injected. This issue spawned this StackOverflow question. There weren't many answers, but most suggested that I try compile-time weaving instead due to greater reliability.
I installed the AspectJ plug-in for Eclipse and Maven. Both of these produce what appears to be properly compiled classes. I've opened up one of the classes in a text editor before AspectJ compilation and found no references to AspectJ. I opened it up after AspectJ compilation and both Eclipse and Maven generated versions have a reference to org.aspectj.weaver.MethodDeclarationLineNumber. This is why I assume it's being properly compiled. The problem is that once deployed, no dependencies get injected.
My Spring applicationContext.xml does include the following:
<context:spring-configured />
<context:component-scan base-package="com.myapp" />
Is the above all that's needed for classes marked @Configurable to have DI done? During the conversion from load-time weaving to compile-time weaving, I removed META-INF/aop.xml, <context:load-time-weaver /> from my applicationContext.xml, and Spring's Tomcat weaver from my context.xml.
How can I investigate this problem further? What are possible causes?
It works for us on maven using compile time weaving, try adding the following plugins:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerVersion>1.6</compilerVersion>
<fork>true</fork>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<executions>
<execution>
<id>compile</id>
<configuration>
<source>1.6</source>
<target>1.6</target>
<verbose>false</verbose>
<outxml>true</outxml>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile</id>
<configuration>
<source>1.6</source>
<target>1.6</target>
<verbose>false</verbose>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.4</version>
</dependency>
</dependencies>
</plugin>
Its done as two separate execution steps to allow you to add different aspect libraries for unit testing and compilation.
You'll also need the following dependency added for the spring-aspects library:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<scope>compile</scope>
</dependency>
I successfully configured load-time weaving in my app, if this is an alternative for you.
My environment:
- JDK-1.6
- Spring-2.5.6
- JPA with eclipselink-1.1.0
Configuration details:
Spring XML configuration:
<context:annotation-config/>
<context:spring-configured/>
<context:load-time-weaver/>
<bean id="baseEntity" class="package.name.BaseEntity" scope="prototype">
<property name="historyHandler" ref="historyHandler" />
</bean>
<bean id="historyHandler" class="package.name.HistoryJpaHandler" scope="prototype">
<property name="historyDao" ref="historyDao" />
</bean>
<bean id="historyDao" class="package.name.HistoryJpaDao">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
Spring annotations
@Configurable("baseEntity")
public abstract class BaseEntity
@Configurable("historyHandler")
public class HistoryJpaHandler extends SessionEventAdapter implements HistoryHandler
Java VM Parameter
<JAVA_HOME>/bin/java -javaagent:/full/path/to/spring-agent-2.5.6.jar
Instances of historyHandler and baseEntitty are created by ecliselink. historyHandler in baseEntitty and historyDao in historyHandler is set by load-timeweaving.
You can set the VM Parameter in Eclipse run configuration or in Tomcats catalina.sh/bat.
making a field of a @configurable class Autowired throws NullPointerException if you do not configure your spring properly for this annotation.
follow these steps to make @configurable annotations work properly
This method is called AspectJ build time weaving to inject spring beans to your non-spring-made classes.
First step is to install these plugins in eclipse:
From these two update sites install whatever eclipse suggests:
http://download.eclipse.org/tools/ajdt/43/update
http://dist.springsource.org/release/AJDT/configurator/
After installing,right-click on project and Do:
Configure > Convert to Aspectj
Maven > Update
Next, you need to add these to your pom.xml:
Under Dependencies Add:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.0.2.RELEASE</version>
</dependency>
Under Plugins Add:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.5</version>
<configuration>
<showWeaveInfo>true</showWeaveInfo>
<source>1.7</source>
<target>1.7</target>
<Xlint>ignore</Xlint>
<complianceLevel>1.7</complianceLevel>
<encoding>UTF-8</encoding>
<verbose>false</verbose>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.7.0</version>
</dependency>
</dependencies>
</plugin>
Important: DO NOT use any <pluginManagment>
tag under <build>
tag.
your pom.xml needs to be something like this:
<project ....>
....
<dependencies>
<dependency>
....
</dependency>
....
</dependencies>
<build>
<plugins>
<plugin>
....
</plugin>
....
</plugins>
</build>
</project>
finally add <context:spring-configured />
to your spring application context config file.
Now you can annotate a POJO class as @Configurable
and inject spring beans in it using @Autowired
annotation. this way whenever you make a new instance of that POJO it will be configured (e.g. injected with dependencies) automatically.
As far as your Eclipse classpath issues are concerned, you might find this useful.
The m2eclipse plugin has an optional AJDT integration. The integration reads the aspectLibraries section of the aspectj-maven-plugin's configuration, and contributes the jars to Eclipse's Aspect Path.