1

I want to use the JPA EntityListener to support spring security ACLs. On @PostPersist events, I create a permission corresponding to the persisted entity.

I need this operation to participate to the current Transaction. For this to happen I need to have a reference to the application TransactionManager in the EntityListener.

The problem is, Spring can't manage the EntityListener as it is created automatically when EntityManagerFactory is instantiated. And in a classic Spring app, the EntityManagerFactory is itself created during the TransactioManager instantiation.

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

So I have no way to inject the TransactionManager with the constructor, as it is not yet instantiated.

Making the EntityManager a @Component create another instance of the EntityManager. Implementing InitiliazingBean and using afterPropertySet() doesn't work as it's not a Spring managed bean.

Any idea would be helpful as I'm stuck and out of ideas.

Bharat Sinha
  • 13,973
  • 6
  • 39
  • 63
nodje
  • 299
  • 1
  • 4
  • 14

2 Answers2

1

In addition to nodje's instruction you should add one more thing - add AnnotationBeanConfigurerAspect as dependency for your entity manager, otherwise your entity listeners will be created BEFORE spring context will be initialized:

<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
    depends-on="org.springframework.context.config.internalBeanConfigurerAspect">
Andrej Urvantsev
  • 466
  • 4
  • 15
  • And one more thing here. If you use DB as storage for your quartz scheduler, then don't set JpaTransactionManager as transaction manager for quartz, otherwise you'll get circular dependency. – Andrej Urvantsev Sep 21 '12 at 08:18
0

A solution is to use Spring's @Configurable annotation on the EntityListener.

It should in theory allow a non Spring managed instance, the EntityListener in my case, to be aspect woven and thus allowing this instance to get DI.

So here're the different steps:

  • add @Configurable to the EntityListener and @Autowired on the filed to inject (TransactionManager here)
  • add <context:spring-configured/> to the Spring context
  • use aspects-maven-plugin to do Compile Time Weaving (see config below)

So far so good, but it's not working for me. The logs says the EntityListerner is woven:

[INFO] Extending interface set for type 'org.project.commons.security.DefaultEntityListener' (DefaultEntityListener.java) to include 'org.springframework.beans.factory.aspectj.ConfigurableObject' (AnnotationBeanConfigurerAspect.aj)
[INFO] Join point 'initialization(void org.springframework.beans.factory.aspectj.ConfigurableObject.<init>())' in Type 'org.project.commons.security.DefaultEntityListener' (DefaultEntityListener.java:38) advised by before advice from 'org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect' (spring-aspects-3.1.2.RELEASE.jar!AbstractDependencyInjectionAspect.class:78(from AbstractDependencyInjectionAspect.aj)) [with runtime test]
[INFO] Join point 'initialization(void org.springframework.beans.factory.aspectj.ConfigurableObject.<init>())' in Type 'org.project.commons.security.DefaultEntityListener' (DefaultEntityListener.java:38) advised by afterReturning advice from 'org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect' (spring-aspects-3.1.2.RELEASE.jar!AbstractDependencyInjectionAspect.class:87(from AbstractDependencyInjectionAspect.aj)) [with runtime test]
[INFO] Join point 'initialization(void org.project.commons.security.DefaultEntityListener.<init>())' in Type 'org.project.commons.security.DefaultEntityListener' (DefaultEntityListener.java:38) advised by afterReturning advice from 'org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect' (spring-aspects-3.1.2.RELEASE.jar!AbstractDependencyInjectionAspect.class:87(from AbstractDependencyInjectionAspect.aj)) [with runtime test]

but I never get the expected injection.

I anyone has a clue, I welcome it...

        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>1.4</version>
            <configuration>
                <showWeaveInfo>true</showWeaveInfo>
                <proceedOnError>true</proceedOnError>
                <outxml>true</outxml>
                <source>1.6</source>
                <target>1.6</target>
                <complianceLevel>1.6</complianceLevel>
                <encoding>${encoding}</encoding>
                <aspectLibraries>
                    <aspectLibrary>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-aspects</artifactId>
                    </aspectLibrary>
                </aspectLibraries>
                <weaveDependencies>
                    <weaveDependency>
                        <groupId>org.project</groupId>
                        <artifactId>commons</artifactId>
                    </weaveDependency>
                </weaveDependencies>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                        <!--<goal>test-compile</goal>-->
                    </goals>
                </execution>
            </executions>
        </plugin>
nodje
  • 299
  • 1
  • 4
  • 14