Uploaded image for project: 'WildFly'
  1. WildFly
  2. WFLY-2387

CDI injection in entity listeners failing

    Details

      Description

      When trying to use CDI injection in JPA entity listeners, deployment fails with the following exception:

      16:16:37,448 ERROR [org.jboss.msc.service.fail] (ServerService Thread Pool -- 15) MSC000001: Failed to start service jboss.persistenceunit."inject-ear.ear#primary": org.jboss.msc.service.StartException in service jboss.persistenceunit."inject-ear.ear#primary": java.lang.IllegalStateException: JBAS016071: Singleton not set for org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl$AggregatedClassLoader@4eeb95dc. This means that you are trying to access a weld deployment with a Thread Context ClassLoader that is not associated with the deployment.
      	at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1$1.run(PersistenceUnitServiceImpl.java:169)
      	at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1$1.run(PersistenceUnitServiceImpl.java:117)
      	at java.security.AccessController.doPrivileged(Native Method) [rt.jar:1.7.0_25]
      	at org.wildfly.security.manager.WildFlySecurityManager.doChecked(WildFlySecurityManager.java:463) [wildfly-security-manager-1.0.0.Beta3.jar:1.0.0.Beta3]
      	at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1.run(PersistenceUnitServiceImpl.java:178)
      	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [rt.jar:1.7.0_25]
      	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [rt.jar:1.7.0_25]
      	at java.lang.Thread.run(Thread.java:724) [rt.jar:1.7.0_25]
      	at org.jboss.threads.JBossThread.run(JBossThread.java:122) [jboss-threads-2.1.1.Final.jar:2.1.1.Final]
      Caused by: java.lang.IllegalStateException: JBAS016071: Singleton not set for org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl$AggregatedClassLoader@4eeb95dc. This means that you are trying to access a weld deployment with a Thread Context ClassLoader that is not associated with the deployment.
      	at org.jboss.as.weld.services.ModuleGroupSingletonProvider$TCCLSingleton.get(ModuleGroupSingletonProvider.java:75)
      	at org.jboss.as.weld.services.ModuleGroupSingletonProvider$TCCLSingleton.get(ModuleGroupSingletonProvider.java:128)
      	at org.jboss.weld.Container.instance(Container.java:65)
      	at org.jboss.weld.manager.BeanManagerImpl.getBeans(BeanManagerImpl.java:563)
      	at org.jboss.weld.injection.FieldInjectionPoint.inject(FieldInjectionPoint.java:90)
      	at org.jboss.weld.util.Beans.injectBoundFields(Beans.java:358)
      	at org.jboss.weld.util.Beans.injectFieldsAndInitializers(Beans.java:369)
      	at org.jboss.weld.injection.producer.DefaultInjector.inject(DefaultInjector.java:72)
      	at org.jboss.weld.injection.producer.ResourceInjector.inject(ResourceInjector.java:60)
      	at org.jboss.weld.injection.producer.DefaultInjector$1.proceed(DefaultInjector.java:66)
      	at org.jboss.weld.injection.InjectionContextImpl.run(InjectionContextImpl.java:48)
      	at org.jboss.weld.injection.producer.DefaultInjector.inject(DefaultInjector.java:64)
      	at org.jboss.weld.injection.producer.BasicInjectionTarget.inject(BasicInjectionTarget.java:90)
      	at org.hibernate.jpa.event.internal.jpa.BeanManagerListenerFactory$BeanMetaData.<init>(BeanManagerListenerFactory.java:82)
      	at org.hibernate.jpa.event.internal.jpa.BeanManagerListenerFactory$BeanMetaData.<init>(BeanManagerListenerFactory.java:71)
      	at org.hibernate.jpa.event.internal.jpa.BeanManagerListenerFactory.buildListener(BeanManagerListenerFactory.java:57)
      	at org.hibernate.jpa.event.internal.jpa.LegacyCallbackProcessor.resolveCallbacks(LegacyCallbackProcessor.java:168)
      	at org.hibernate.jpa.event.internal.jpa.LegacyCallbackProcessor.processCallbacksForEntity(LegacyCallbackProcessor.java:71)
      	at org.hibernate.jpa.event.spi.JpaIntegrator.integrate(JpaIntegrator.java:150)
      	at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:310)
      	at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1837)
      	at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:854)
      	at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:847)
      	at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:396)
      	at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:846)
      	at org.jboss.as.jpa.hibernate4.TwoPhaseBootstrapImpl.build(TwoPhaseBootstrapImpl.java:44)
      	at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1$1.run(PersistenceUnitServiceImpl.java:151)
      	... 8 more
      

      I've created a small showcase of the problem: https://github.com/papegaaij/listener-injection

        Gliffy Diagrams

          Issue Links

            Activity

            Hide
            sebersole Steve Ebersole added a comment -

            Don't forget that in the short-term there is also https://hibernate.atlassian.net/browse/HHH-10477.

            Tiny Pics Did you try https://hibernate.atlassian.net/browse/HHH-10477 as well?

            We all agree that that https://hibernate.atlassian.net/browse/HHH-8706 + some changes in WildFly/Weld (and ultimately propogating up to JPA/CDI) is the correct solution moving forward. However any changes for that are only done so far on the Hibernate side as Scott Marlow points out.

            Show
            sebersole Steve Ebersole added a comment - Don't forget that in the short-term there is also https://hibernate.atlassian.net/browse/HHH-10477 . Tiny Pics Did you try https://hibernate.atlassian.net/browse/HHH-10477 as well? We all agree that that https://hibernate.atlassian.net/browse/HHH-8706 + some changes in WildFly/Weld (and ultimately propogating up to JPA/CDI) is the correct solution moving forward. However any changes for that are only done so far on the Hibernate side as Scott Marlow points out.
            Hide
            meetoblivion John Ament added a comment -

            Its a little odd, shouldn't hibernate just look up the entity listener when needed at runtime, instead of eagerly loading it?

            I don't recall the spec requiring things like entity listener being app scoped, which this seems to assume.

            Show
            meetoblivion John Ament added a comment - Its a little odd, shouldn't hibernate just look up the entity listener when needed at runtime, instead of eagerly loading it? I don't recall the spec requiring things like entity listener being app scoped, which this seems to assume.
            Hide
            smarlow Scott Marlow added a comment -

            John, "hibernate.delay_cdi_access" controls that. Keep in mind that with entity listener registration delayed to runtime, an unexpected deployment failure could occur at run time. I'm curious as to what the typical deployment errors might be that show up at runtime.

            I don't recall the spec requiring things like entity listener being app scoped, which this seems to assume.

            http://docs.oracle.com/javaee/6/tutorial/doc/gjbbk.html is a nice summary of the different scopes. If the entity listener scope is not ApplicationScoped, which other scopes do you think could make sense?

            The HHH-10477 change will be in the Hibernate 5.0.8 release (you could build the ORM 5.0 branch now if you like). If anyone tries this out with a real application (under some test load), it would be interesting to hear how the runtime initialization works out for multiple concurrent threads that are all loading an entity for the first time. So, that perhaps, you would simulate what happens when N threads all need to make their first use of the entity listener. Thanks to anyone that can try this.

            Show
            smarlow Scott Marlow added a comment - John, "hibernate.delay_cdi_access" controls that. Keep in mind that with entity listener registration delayed to runtime, an unexpected deployment failure could occur at run time. I'm curious as to what the typical deployment errors might be that show up at runtime. I don't recall the spec requiring things like entity listener being app scoped, which this seems to assume. http://docs.oracle.com/javaee/6/tutorial/doc/gjbbk.html is a nice summary of the different scopes. If the entity listener scope is not ApplicationScoped, which other scopes do you think could make sense? The HHH-10477 change will be in the Hibernate 5.0.8 release (you could build the ORM 5.0 branch now if you like). If anyone tries this out with a real application (under some test load), it would be interesting to hear how the runtime initialization works out for multiple concurrent threads that are all loading an entity for the first time. So, that perhaps, you would simulate what happens when N threads all need to make their first use of the entity listener. Thanks to anyone that can try this.
            Hide
            smarlow Scott Marlow added a comment - - edited

            From JPA 2.1 section 3.5.1 Entity Listeners:

            ...
            When invoked from within a Java EE environment, the callback listeners for an entity share the enter-
            prise naming context of the invoking component, and the entity callback methods are invoked in the
            transaction and security contexts of the calling component at the time at which the callback method is
            invoked. [45]
            [45] For example, if a transaction commit occurs as a result of the normal termination of a session bean business method with transac-
            tion attribute RequiresNew, the PostPersist and PostRemove callbacks are executed in the naming context, the transac-
            tion context, and the security context of that component.

            John, I'm also not exactly sure how the entity listener scope impacts this jira exactly.

            Show
            smarlow Scott Marlow added a comment - - edited From JPA 2.1 section 3.5.1 Entity Listeners: ... When invoked from within a Java EE environment, the callback listeners for an entity share the enter- prise naming context of the invoking component, and the entity callback methods are invoked in the transaction and security contexts of the calling component at the time at which the callback method is invoked. [45] [45] For example, if a transaction commit occurs as a result of the normal termination of a session bean business method with transac- tion attribute RequiresNew, the PostPersist and PostRemove callbacks are executed in the naming context, the transac- tion context, and the security context of that component. John, I'm also not exactly sure how the entity listener scope impacts this jira exactly.
            Hide
            meetoblivion John Ament added a comment -

            The impression that I have from looking through this ticket, as well as the relevant HHH tickets, is that the assumption is that an entity listener is booted on start up of the persistence unit. While this is probably true of a non-CDI managed one, I would expect the entity listener to be looked up when needed to perform an operation instead of eagerly being initialized. This is the part where I think scoping may have some kind of impact.

            Suppose I have

            @RequestScoped
            public class MyListener implements EntityListener

            { .. }

            I would expect that this listener is used whenever needed within a single HTTP request. I think (and I haven't tested this yet) that instead a more global listener is used, probably created during app start up. Maybe I'm making a wild assumption, that's why I'm bringing it up to see what you think.

            Granted, the JPA spec doesn't use the term contextual reference, so I'm not sure if I'm reading too much between the lines either.

            How does this relate to this ticket? Well, these are two points. Probably the third is that if I'm starting up an application, I have various scopes active during start up. I might be doing work with JPA before CDI is fully loaded. The only valid places to do stuff like this is in AfterDeploymentValidation, the PostConstruct methods on app scoped beans, and observers for initialized application scoped events. In all of those cases, CDI should be fully running and JPA could in theory wait until that point to get its references to an entity listener needed for those operations, assuming there are no cyclic dependencies.

            Show
            meetoblivion John Ament added a comment - The impression that I have from looking through this ticket, as well as the relevant HHH tickets, is that the assumption is that an entity listener is booted on start up of the persistence unit. While this is probably true of a non-CDI managed one, I would expect the entity listener to be looked up when needed to perform an operation instead of eagerly being initialized. This is the part where I think scoping may have some kind of impact. Suppose I have @RequestScoped public class MyListener implements EntityListener { .. } I would expect that this listener is used whenever needed within a single HTTP request. I think (and I haven't tested this yet) that instead a more global listener is used, probably created during app start up. Maybe I'm making a wild assumption, that's why I'm bringing it up to see what you think. Granted, the JPA spec doesn't use the term contextual reference, so I'm not sure if I'm reading too much between the lines either. How does this relate to this ticket? Well, these are two points. Probably the third is that if I'm starting up an application, I have various scopes active during start up. I might be doing work with JPA before CDI is fully loaded. The only valid places to do stuff like this is in AfterDeploymentValidation, the PostConstruct methods on app scoped beans, and observers for initialized application scoped events. In all of those cases, CDI should be fully running and JPA could in theory wait until that point to get its references to an entity listener needed for those operations, assuming there are no cyclic dependencies.

              People

              • Assignee:
                smarlow Scott Marlow
                Reporter:
                papegaaij Emond Papegaaij
              • Votes:
                25 Vote for this issue
                Watchers:
                41 Start watching this issue

                Dates

                • Created:
                  Updated:

                  Development