3

I use Spring-Data Neo4j 2.2.0-RELEASE. (my following issue would be applicable to any other kind of entity mapping, why not JPA)

In my project, I have a public method annotated with @Transactional Spring's annotation, since I want to update/save an entity inside it:

public class MeetingServices {

    private UserRepository userRepository;

    private MeetingRepository meetingRepository;

    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void setMeetingRepository(MeetingRepository meetingRepository) {
        this.meetingRepository = meetingRepository;
    }

    @Transactional("neo4jTransactionManager")
    public void save(Meeting meeting) {
        User creator = userRepository.getUserByEmail("test@test.com");
        creator.participateIn(meeting); // this line leads to a NotInTransactionException since it signals that no transaction context is associated.
        meeting.setCreator(creator);
    }

My application-context.xml is the following:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:neo4j="http://www.springframework.org/schema/data/neo4j"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/data/neo4j
       http://www.springframework.org/schema/data/neo4j/spring-neo4j.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <bean id="graphDatabaseService" class="org.neo4j.kernel.EmbeddedGraphDatabase">
        <constructor-arg value="target/neo4jgraph" />
    </bean>

    <neo4j:config graphDatabaseService="graphDatabaseService" />

    <bean id="meetingServices" class="services.MeetingServices">
        <property name="userRepository"><ref bean="userRepository"/></property>
        <property name="meetingRepository"><ref bean="meetingRepository"/></property>
    </bean>

    <bean id="userServices" class="services.UserServices">
        <property name="userRepository"><ref bean="userRepository"/></property>
    </bean>

    <bean id="neo4jTransactionManager"
        class="org.springframework.transaction.jta.JtaTransactionManager">
        <property name="transactionManager">
            <bean class="org.neo4j.kernel.impl.transaction.SpringTransactionManager">
                <constructor-arg ref="graphDatabaseService" />
            </bean>
        </property>
        <property name="userTransaction">
            <bean class="org.neo4j.kernel.impl.transaction.UserTransactionImpl">
                <constructor-arg ref="graphDatabaseService" />
            </bean>
        </property>
    </bean>

    <tx:annotation-driven mode="aspectj"
        transaction-manager="neo4jTransactionManager" />

    <!-- auto-generated repositories for Neo4j storage -->
    <neo4j:repositories base-package="repositories"/> 

    <context:spring-configured/>

    <context:annotation-config/>

</beans>

As we see in this configuration, aspectJ is used for transactions.

So, I tried to test another way of doing by changing my application-context.xml to use the proxy feature instead of aspectJ feature:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:neo4j="http://www.springframework.org/schema/data/neo4j"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/data/neo4j
       http://www.springframework.org/schema/data/neo4j/spring-neo4j.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <bean id="graphDatabaseService" class="org.neo4j.kernel.EmbeddedGraphDatabase">
        <constructor-arg value="target/neo4jgraph" />
    </bean>

    <neo4j:config graphDatabaseService="graphDatabaseService" />

    <bean id="meetingServices" class="services.MeetingServices">
        <property name="userRepository"><ref bean="userRepository"/></property>
        <property name="meetingRepository"><ref bean="meetingRepository"/></property>
    </bean>

    <bean id="userServices" class="services.UserServices">
        <property name="userRepository"><ref bean="userRepository"/></property>
    </bean>

    <tx:annotation-driven mode="proxy" />


    <neo4j:repositories base-package="repositories"/>

    <context:spring-configured/>

    <context:annotation-config/>

</beans>

This configuration works pretty well since @Transactional (whose neo4jTransactionManager parameter was of course removed) annotation is now taken in account for my service's method.

My question is, (no matter whether my project would work with simple proxy method):

What did I miss or misconfigure in my first Spring's configuration that makes aspectJ transaction features failed?

I'm currently improving my technical skills with Spring, and read few articles about "Load-time weaving" for aspectJ. Might this be linked to my issue?

Mik378
  • 21,881
  • 15
  • 82
  • 180

1 Answers1

3

Try adding <context:load-time-weaver/> to enable load time weaving and add the spring-aspects.jar to the classpath.

See http://static.springsource.org/spring/docs/current/spring-framework-reference/html/aop.html#aop-aj-ltw-spring for more info

Edit

For generic java applications, ie not running in a web or application container, you need to enable the java instrumentatioin via a javaagent option:

java -javaagent:path/to/spring-instrument.jar your.Main

If you want to weaving your own aspects, you need to provide a META-INF/aop.xml file with aspect declarations. (Not requiered for spring only aspects, it's already provided on spring-aspect.jar).

Finally you can use compile time weaving instead, using the maven aspectj plugin, for example:

<plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <configuration>
                <complianceLevel>1.6</complianceLevel>
                <aspectLibraries>
                    <aspectLibrary>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-aspects</artifactId>
                    </aspectLibrary>
                </aspectLibraries>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
Jose Luis Martin
  • 10,459
  • 1
  • 37
  • 38
  • I already tried this, but I end up with this: `Caused by: java.lang.IllegalStateException: ClassLoader [sun.misc.Launcher$AppClassLoader] does NOT provide an 'addTransformer(ClassFileTransformer)' method. Specify a custom LoadTimeWeaver or start your Java virtual machine with Spring's agent: -javaagent:org.springframework.instrument.jar` – Mik378 Mar 25 '13 at 14:26
  • Add the option for the Main launcher: java -javaagent:C:/projects/foo/lib/global/spring-instrument.jar foo.Main as in reference example – Jose Luis Martin Mar 25 '13 at 14:43
  • I've just followed your advice :) but that leads to this: Caused by: `java.lang.VerifyError: (class: services/MeetingServices$$EnhancerByCGLIB$$73b088b5, method: setMeetingRepository signature: (Lrepositories/MeetingRepository;)V) Inconsistent stack height 1 != 0`. Sounds like a known bug (http://stackoverflow.com/questions/9027009/aspectj-verifyerror). I use Java 7 .. I've just tried the advice: adding `-XX:-UseSplitVerifier`to VM options but error still occurs. – Mik378 Mar 25 '13 at 15:07
  • Try with maven and compile time weaving. I just post an example. drop the ltw tag and the javaagent option. they are not requiered when using compile time weaving. – Jose Luis Martin Mar 25 '13 at 15:14
  • Thanks, I will try that (maven method) as soon as I come back to my computer, I'll inform you :) – Mik378 Mar 25 '13 at 16:05
  • The plugin doesn't work in eclipse. Following guidance in http://stackoverflow.com/questions/6522540/maven-ajdt-project-in-eclipse ...AJDT m2e Configurator fails during installation. ...uninstall m2eclipse..install AJDT m2e Configurator still fails...install aspectJ development tools (Juno)..install AJDT m2e Configurator with m2e...and finally working with this config http://stackoverflow.com/questions/6844603/how-to-create-a-maven-project-in-eclipse-with-aspectj-support. What a PITA! Now aspectJ is weaved at compile time, but still no transactions. – s_t_e_v_e Aug 04 '13 at 22:44