Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't AspectJ compile-time weaving of Spring's @Configurable work?

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?

like image 203
Robert Campbell Avatar asked May 23 '09 14:05

Robert Campbell


People also ask

What is AspectJ weaving?

Weaving in AspectJ The weaving process consists of executing the aspect advice to produce only a set of generated classes that have the aspect implementation code woven into it. The example at right shows a potential implementation of an aspect which logs the entry and exit of all methods.

What is the use of AspectJ in spring?

@AspectJ refers to a style of declaring aspects as regular Java classes annotated with Java 5 annotations. The @AspectJ support is enabled by including the following element inside your XML Schema-based configuration file.

What is weaving in Spring AOP?

Weaving: linking aspects with other application types or objects to create an advised object. This can be done at compile time (using the AspectJ compiler, for example), load time, or at runtime. Spring AOP, like other pure Java AOP frameworks, performs weaving at runtime.


4 Answers

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>
like image 114
Stephen Houston Avatar answered Oct 05 '22 19:10

Stephen Houston


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.

like image 30
uı6ʎɹnɯ ꞁəıuɐp Avatar answered Oct 05 '22 18:10

uı6ʎɹnɯ ꞁəıuɐp


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.

like image 26
Meysam Feghhi Avatar answered Oct 05 '22 18:10

Meysam Feghhi


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.

like image 40
Rich Seller Avatar answered Oct 05 '22 19:10

Rich Seller