Announcement Announcement Module
Collapse
No announcement yet.
Is it possible to use @Configurable on JPA EntityListeners? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Is it possible to use @Configurable on JPA EntityListeners?

    Hi,

    I'm trying to create an EntityListener that needs access to one of my beans, so I would like Spring to inject it. I haven't found relevant documentation for this use case, so I'm not even sure if this can be accomplished.

    If I create the entity listener class as an inner static class inside the entity, compilation goes fine, but no injection happens. If I declare the entity listener as an external class, AspectJ weaving fails badly with several StackOverflowError.

    My scenario:
    - Spring 3.0.1 (snapshot)
    - AspectJ 1.6.7
    - Using compile time weaving

    These are the two declarations of the Entity Listener:

    As an inner static class (no injection happens):

    Code:
    @EntityListeners({AbstractOwnedEntity.CreatorAssigner.class})
    @MappedSuperclass
    public abstract class AbstractOwnedEntity extends AbstractBaseEntity {
    
        [...]
    
        @Configurable(autowire = Autowire.BY_TYPE, dependencyCheck = true)
        public static class CreatorAssigner {
    
            @Autowired
            private SecurityHelper securityHelper;
    
            @PrePersist
            public void onPrePersist(AbstractOwnedEntity abstractOwnedEntity) {
                [...]
            }
        }
    }
    As an external class, AspectJ compile time weaving fails:

    Code:
    @EntityListeners({CreatorAssigner.class})
    @MappedSuperclass
    public abstract class AbstractOwnedEntity extends AbstractBaseEntity {
    
        [...]
    
    }
    
    @Configurable(autowire = Autowire.BY_TYPE, dependencyCheck = true)
    public class CreatorAssigner {
    
        @Autowired
        private SecurityHelper securityHelper;
    
        @PrePersist
        public void onPrePersist(AbstractOwnedEntity abstractOwnedEntity) {
            [...]
        }
    }

    As an additional note, I know I can use @Configurable directly in the entity and use a @PrePersist callback directly (and I have checked that it works fine), but I would rather not make all the entities configurable if it can be worked out with an entity listener.

  • #2
    This should work. Who creates CreatorAssigner?

    As for the StackOverflowError, you should file a bug report at http://eclipse.org/aspectj/bugs.php. Usually, such bugs are given a high priority, so that might help you fairly quickly.

    -Ramnivas

    Comment


    • #3
      Originally posted by ramnivas View Post
      This should work. Who creates CreatorAssigner?
      It should be instantiated by the JPA implementation. In my case, this is Hibernate 3.5.

      As for the StackOverflowError, you should file a bug report at http://eclipse.org/aspectj/bugs.php. Usually, such bugs are given a high priority, so that might help you fairly quickly.
      Thanks, I wasn't sure if it was a bug in AspectJ or simply bad usage in my side. I will report the bug.

      Comment


      • #4
        Can you verify that CreatorAssigner is actually created, perhaps by adding a log statement to its constructor? Also, you can verify that the class is being woven by updating aop.xml as described in http://forum.springsource.org/showpo...00&postcount=6

        -Ramnivas

        Comment


        • #5
          The weaving errors dissapeared when I upgraded to AspectJ 1.6.8. It seems like this was a known bug:
          https://bugs.eclipse.org/bugs/show_bug.cgi?id=298908

          Originally posted by ramnivas View Post
          Can you verify that CreatorAssigner is actually created, perhaps by adding a log statement to its constructor?
          It is created. This is the stacktrace when it gets instantiated:
          Code:
          at myproject.domain.AbstractOwnedEntity$CreatorAssigner.<init>(AbstractOwnedEntity.java:82)
          	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
          	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
          	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
          	at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
          	at java.lang.Class.newInstance0(Class.java:355)
          	at java.lang.Class.newInstance(Class.java:308)
          	at org.hibernate.ejb.event.CallbackResolver.resolveCallback(CallbackResolver.java:154)
          	at org.hibernate.ejb.event.EntityCallbackHandler.addCallback(EntityCallbackHandler.java:108)
          	at org.hibernate.ejb.event.EntityCallbackHandler.add(EntityCallbackHandler.java:53)
          	at org.hibernate.ejb.EventListenerConfigurator.configure(EventListenerConfigurator.java:201)
          	at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:1044)
          	at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:640)
          	at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:72)
          	at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:225)
          	at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:308)
          	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1457)
          	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1397)
          	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513)
          	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:450)
          	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:290)
          	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
          	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:287)
          	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
          	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:386)
          	at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:266)
          	at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.detectPersistenceExceptionTranslators(PersistenceExceptionTranslationInterceptor.java:139)
          	at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.<init>(PersistenceExceptionTranslationInterceptor.java:79)
          	at org.springframework.dao.annotation.PersistenceExceptionTranslationAdvisor.<init>(PersistenceExceptionTranslationAdvisor.java:70)
          	at org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor.setBeanFactory(PersistenceExceptionTranslationPostProcessor.java:99)
          	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeAwareMethods(AbstractAutowireCapableBeanFactory.java:1419)
          	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1388)
          	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513)
          	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:450)
          	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:290)
          	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
          	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:287)
          	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
          	at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:687)
          	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:408)
          	at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:272)
          	at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:196)
          	at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:47)
          	at org.eclipse.jetty.server.handler.ContextHandler.startContext(ContextHandler.java:645)
          	at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:189)
          	at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:978)
          	at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:586)
          	at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:349)
          	at org.mortbay.jetty.plugin.JettyWebAppContext.doStart(JettyWebAppContext.java:102)
          	at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:55)
          	at org.eclipse.jetty.server.handler.HandlerCollection.doStart(HandlerCollection.java:165)
          	at org.eclipse.jetty.server.handler.ContextHandlerCollection.doStart(ContextHandlerCollection.java:162)
          	at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:55)
          	at org.eclipse.jetty.server.handler.HandlerCollection.doStart(HandlerCollection.java:165)
          	at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:55)
          	at org.eclipse.jetty.server.handler.HandlerWrapper.doStart(HandlerWrapper.java:92)
          	at org.eclipse.jetty.server.Server.doStart(Server.java:228)
          	at org.mortbay.jetty.plugin.JettyServer.doStart(JettyServer.java:69)
          	at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:55)
          	at org.mortbay.jetty.plugin.AbstractJettyMojo.startJetty(AbstractJettyMojo.java:433)
          	at org.mortbay.jetty.plugin.AbstractJettyMojo.execute(AbstractJettyMojo.java:377)
          	at org.mortbay.jetty.plugin.JettyRunMojo.execute(JettyRunMojo.java:546)
          	at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:490)
          	at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:694)
          	at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeStandaloneGoal(DefaultLifecycleExecutor.java:569)
          	at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(DefaultLifecycleExecutor.java:539)
          	at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHandleFailures(DefaultLifecycleExecutor.java:387)
          	at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegments(DefaultLifecycleExecutor.java:348)
          	at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLifecycleExecutor.java:180)
          	at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:328)
          	at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:138)
          	at org.apache.maven.cli.MavenCli.main(MavenCli.java:362)
          	at org.apache.maven.cli.compat.CompatibleMain.main(CompatibleMain.java:60)
          	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
          	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
          	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
          	at java.lang.reflect.Method.invoke(Method.java:597)
          	at org.codehaus.classworlds.Launcher.launchEnhanced(Launcher.java:315)
          	at org.codehaus.classworlds.Launcher.launch(Launcher.java:255)
          	at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)
          	at org.codehaus.classworlds.Launcher.main(Launcher.java:375)
          Hibernate creates it when initializing the JPA container.

          Also, you can verify that the class is being woven by updating aop.xml as described in http://forum.springsource.org/showpo...00&postcount=6
          Maybe I got this wrong, but I thought that when using compile time weaving the aop.xml file wasn't needed? I still tested adding it with the -verbose and -showWeaveInfo flags and noticed no differences.

          Comment


          • #6
            I configured the CTW compilation to output the weaving info. This is the relevant info:

            When CreatorAssigner is an external class:
            Code:
            [INFO] Extending interface set for type 'myproject.domain.CreatorAssigner' (CreatorAssigner.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 'myproject.domain.CreatorAssigner' (CreatorAssigner.java:19) advised by before advice from 'org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect' (spring-aspects-3.0.1.BUILD-SNAPSHOT.jar!AbstractDependencyInjectionAspect.class:78(from AbstractDependencyInjectionAspect.aj)) [with runtime test]
            [INFO] Join point 'initialization(void org.springframework.beans.factory.aspectj.ConfigurableObject.<init>())' in Type 'myproject.domain.CreatorAssigner' (CreatorAssigner.java:19) advised by afterReturning advice from 'org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect' (spring-aspects-3.0.1.BUILD-SNAPSHOT.jar!AbstractDependencyInjectionAspect.class:87(from AbstractDependencyInjectionAspect.aj)) [with runtime test]
            [INFO] Join point 'initialization(void myproject.domain.CreatorAssigner.<init>())' in Type 'myproject.domain.CreatorAssigner' (CreatorAssigner.java:19) advised by afterReturning advice from 'org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect' (spring-aspects-3.0.1.BUILD-SNAPSHOT.jar!AbstractDependencyInjectionAspect.class:87(from AbstractDependencyInjectionAspect.aj)) [with runtime test]
            When CreatorAssigner is a static inner class of AbstractOwnedEntity:
            Code:
            [INFO] Join point 'initialization(void myproject.domain.AnonymousVote.<init>())' in Type 'myproject.domain.AnonymousVote' (AnonymousVote.java:14) advised by afterReturning advice from 'org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect' (spring-aspects-3.0.1.BUILD-SNAPSHOT.jar!AbstractDependencyInjectionAspect.class:87(from AbstractDependencyInjectionAspect.aj)) [with runtime test]
            [INFO] Extending interface set for type 'myproject.domain.AbstractOwnedEntity' (AbstractOwnedEntity.java) to include 'org.springframework.beans.factory.aspectj.ConfigurableObject' (AnnotationBeanConfigurerAspect.aj)
            [INFO] Extending interface set for type 'myproject.domain.AbstractOwnedEntity' (AbstractOwnedEntity.java) to include 'org.springframework.beans.factory.aspectj.AbstractInterfaceDrivenDependencyInjectionAspect$ConfigurableDeserializationSupport' (AnnotationBeanConfigurerAspect.aj)
            [INFO] Type 'myproject.domain.AbstractOwnedEntity' (AbstractOwnedEntity.java) has intertyped method from 'org.springframework.beans.factory.aspectj.AbstractInterfaceDrivenDependencyInjectionAspect' (AbstractInterfaceDrivenDependencyInjectionAspect.aj:'java.lang.Object org.springframework.beans.factory.aspectj.AbstractInterfaceDrivenDependencyInjectionAspect$ConfigurableDeserializationSupport.readResolve()')
            [INFO] Join point 'initialization(void org.springframework.beans.factory.aspectj.ConfigurableObject.<init>())' in Type 'myproject.domain.AbstractOwnedEntity' (AbstractOwnedEntity.java:47) advised by before advice from 'org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect' (spring-aspects-3.0.1.BUILD-SNAPSHOT.jar!AbstractDependencyInjectionAspect.class:78(from AbstractDependencyInjectionAspect.aj)) [with runtime test]
            [INFO] Join point 'initialization(void org.springframework.beans.factory.aspectj.ConfigurableObject.<init>())' in Type 'myproject.domain.AbstractOwnedEntity' (AbstractOwnedEntity.java:47) advised by afterReturning advice from 'org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect' (spring-aspects-3.0.1.BUILD-SNAPSHOT.jar!AbstractDependencyInjectionAspect.class:87(from AbstractDependencyInjectionAspect.aj)) [with runtime test]
            [INFO] Join point 'initialization(void myproject.domain.AbstractOwnedEntity.<init>())' in Type 'myproject.domain.AbstractOwnedEntity' (AbstractOwnedEntity.java:47) advised by afterReturning advice from 'org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect' (spring-aspects-3.0.1.BUILD-SNAPSHOT.jar!AbstractDependencyInjectionAspect.class:87(from AbstractDependencyInjectionAspect.aj)) [with runtime test]
            In both cases I can confirm that CreatorAssigner is instantiated and dependencies are not being injected.

            Comment


            • #7
              more info please

              Could you please shed a light on how your compile time weaving is configured?

              Comment


              • #8
                Sure, I configured it using the aspectj maven plugin.

                From my pom.xml
                Code:
                <plugin>
                                <groupId>org.codehaus.mojo</groupId>
                                <artifactId>aspectj-maven-plugin</artifactId>
                                <configuration>
                                    <verbose>true</verbose>
                                    <showWeaveInfo>true</showWeaveInfo>
                                    <complianceLevel>1.6</complianceLevel>
                                    <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>aspectjtools</artifactId>
                				<version>${aspectj.version}</version>
                			</dependency>
                		</dependencies>
                </plugin>

                Comment

                Working...
                X