Search code examples
javaasynchronouseventswildflycdi

Java EE 8: No transaction in asynchronous observer (CDI 2.0)


I'm kinda stuck with a problem that - I guess - is pretty common.

I run a Wildfly 12 with Java EE 8 profile enabled (including CDI 2.0) and I'm using JTA.

So what's the problem: I have an @ApplicationScoped bean that fires an asynchronous event. Another @ApplicationScoped bean observes this event via @ObservesAsync. Within the observer, I want to process some propagated metadata and also interact with the database. I have a repository class annotated with @Transactional for that. The setup looks like this:

A simple example would look like this:

@ApplicationScoped
public class ClassA {

    @Inject
    private Event<ApplicationStarted> applicationStartedEvent;

    public void initialize(@Observes @Initialized(ApplicationScoped.class) Object init) {
        applicationStartedEvent.fireAsync(new ApplicationStarted());
    }
}
@ApplicationScoped
public class ClassB {

    @Inject
    private Repository repository;

    public void onApplicationStarted(@ObservesAsync ApplicationStarted applicationStarted) {

        repository.getSomethingFromDatabase();
    }
}
@Transactional
@Dependent
public class Repository {

    @PersistenceContext
    private EntityManager entityManager;

    public List<Object> getSomethingFromDatabase() {
        return entityManager.createQuery("from User").getResultList();
    }
}

Unfortunately I can't get this code snippet work. There's a weird exception I don't understand when

repository.getSomethingFromDatabase();

is executed.

17:17:53,611 ERROR [stderr] (Weld Thread Pool -- 3) java.lang.NullPointerException
17:17:53,611 ERROR [stderr] (Weld Thread Pool -- 3)     at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:936)
17:17:53,611 ERROR [stderr] (Weld Thread Pool -- 3)     at org.wildfly.common.context.ContextManager.getPrivileged(ContextManager.java:271)
17:17:53,611 ERROR [stderr] (Weld Thread Pool -- 3)     at org.wildfly.transaction.client.LocalTransactionContext.getCurrent(LocalTransactionContext.java:115)
17:17:53,612 ERROR [stderr] (Weld Thread Pool -- 3)     at org.wildfly.transaction.client.ContextTransactionManager.begin(ContextTransactionManager.java:62)
17:17:53,612 ERROR [stderr] (Weld Thread Pool -- 3)     at org.wildfly.transaction.client.ContextTransactionManager.begin(ContextTransactionManager.java:54)
17:17:53,612 ERROR [stderr] (Weld Thread Pool -- 3)     at com.arjuna.ats.jta.cdi.transactional.TransactionalInterceptorBase.invokeInOurTx(TransactionalInterceptorBase.java:116)
17:17:53,612 ERROR [stderr] (Weld Thread Pool -- 3)     at com.arjuna.ats.jta.cdi.transactional.TransactionalInterceptorRequired.doIntercept(TransactionalInterceptorRequired.java:53)
17:17:53,612 ERROR [stderr] (Weld Thread Pool -- 3)     at com.arjuna.ats.jta.cdi.transactional.TransactionalInterceptorBase.intercept(TransactionalInterceptorBase.java:79)
17:17:53,613 ERROR [stderr] (Weld Thread Pool -- 3)     at com.arjuna.ats.jta.cdi.transactional.TransactionalInterceptorRequired.intercept(TransactionalInterceptorRequired.java:47)
17:17:53,613 ERROR [stderr] (Weld Thread Pool -- 3)     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
17:17:53,613 ERROR [stderr] (Weld Thread Pool -- 3)     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
17:17:53,614 ERROR [stderr] (Weld Thread Pool -- 3)     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
17:17:53,614 ERROR [stderr] (Weld Thread Pool -- 3)     at java.lang.reflect.Method.invoke(Method.java:498)
17:17:53,614 ERROR [stderr] (Weld Thread Pool -- 3)     at org.jboss.weld.interceptor.reader.SimpleInterceptorInvocation$SimpleMethodInvocation.invoke(SimpleInterceptorInvocation.java:73)
17:17:53,614 ERROR [stderr] (Weld Thread Pool -- 3)     at org.jboss.weld.interceptor.proxy.InterceptorMethodHandler.executeAroundInvoke(InterceptorMethodHandler.java:84)
17:17:53,614 ERROR [stderr] (Weld Thread Pool -- 3)     at org.jboss.weld.interceptor.proxy.InterceptorMethodHandler.executeInterception(InterceptorMethodHandler.java:72)
17:17:53,614 ERROR [stderr] (Weld Thread Pool -- 3)     at org.jboss.weld.interceptor.proxy.InterceptorMethodHandler.invoke(InterceptorMethodHandler.java:56)
17:17:53,614 ERROR [stderr] (Weld Thread Pool -- 3)     at org.jboss.weld.bean.proxy.CombinedInterceptorAndDecoratorStackMethodHandler.invoke(CombinedInterceptorAndDecoratorStackMethodHandler.java:79)
17:17:53,615 ERROR [stderr] (Weld Thread Pool -- 3)     at org.jboss.weld.bean.proxy.CombinedInterceptorAndDecoratorStackMethodHandler.invoke(CombinedInterceptorAndDecoratorStackMethodHandler.java:68)
17:17:53,615 ERROR [stderr] (Weld Thread Pool -- 3)     at com.auroraspotter.kp.Repo$Proxy$_$$_WeldSubclass.getSomethingFromDatabase(Unknown Source)
17:17:53,615 ERROR [stderr] (Weld Thread Pool -- 3)     at com.auroraspotter.kp.KpIndexUpdateCronControl.onApplicationStarted(KpIndexUpdateCronControl.java:48)
17:17:53,615 ERROR [stderr] (Weld Thread Pool -- 3)     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
17:17:53,616 ERROR [stderr] (Weld Thread Pool -- 3)     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
17:17:53,616 ERROR [stderr] (Weld Thread Pool -- 3)     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
17:17:53,616 ERROR [stderr] (Weld Thread Pool -- 3)     at java.lang.reflect.Method.invoke(Method.java:498)
17:17:53,616 ERROR [stderr] (Weld Thread Pool -- 3)     at org.jboss.weld.injection.StaticMethodInjectionPoint.invoke(StaticMethodInjectionPoint.java:95)
17:17:53,617 ERROR [stderr] (Weld Thread Pool -- 3)     at org.jboss.weld.injection.StaticMethodInjectionPoint.invoke(StaticMethodInjectionPoint.java:85)
17:17:53,617 ERROR [stderr] (Weld Thread Pool -- 3)     at org.jboss.weld.injection.MethodInvocationStrategy$DefaultMethodInvocationStrategy.invoke(MethodInvocationStrategy.java:109)
17:17:53,617 ERROR [stderr] (Weld Thread Pool -- 3)     at org.jboss.weld.event.ObserverMethodImpl.sendEvent(ObserverMethodImpl.java:330)
17:17:53,617 ERROR [stderr] (Weld Thread Pool -- 3)     at org.jboss.weld.event.ObserverMethodImpl.sendEvent(ObserverMethodImpl.java:308)
17:17:53,617 ERROR [stderr] (Weld Thread Pool -- 3)     at org.jboss.weld.event.ObserverMethodImpl.notify(ObserverMethodImpl.java:286)
17:17:53,617 ERROR [stderr] (Weld Thread Pool -- 3)     at javax.enterprise.inject.spi.ObserverMethod.notify(ObserverMethod.java:124)
17:17:53,617 ERROR [stderr] (Weld Thread Pool -- 3)     at org.jboss.weld.util.Observers.notify(Observers.java:170)
17:17:53,618 ERROR [stderr] (Weld Thread Pool -- 3)     at org.jboss.weld.event.ObserverNotifier.notifyAsyncObserver(ObserverNotifier.java:413)
17:17:53,618 ERROR [stderr] (Weld Thread Pool -- 3)     at org.jboss.weld.event.ObserverNotifier.lambda$notifyAsyncObservers$5(ObserverNotifier.java:356)
17:17:53,618 ERROR [stderr] (Weld Thread Pool -- 3)     at org.jboss.weld.event.ObserverNotifier.lambda$null$8(ObserverNotifier.java:438)
17:17:53,618 ERROR [stderr] (Weld Thread Pool -- 3)     at org.jboss.weld.security.spi.SecurityServices.lambda$getSecurityContextAssociator$0(SecurityServices.java:80)
17:17:53,618 ERROR [stderr] (Weld Thread Pool -- 3)     at org.jboss.weld.event.ObserverNotifier.lambda$createSupplier$9(ObserverNotifier.java:435)
17:17:53,618 ERROR [stderr] (Weld Thread Pool -- 3)     at java.util.concurrent.CompletableFuture$AsyncSupply.run$$$capture(CompletableFuture.java:1590)
17:17:53,618 ERROR [stderr] (Weld Thread Pool -- 3)     at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java)
17:17:53,618 ERROR [stderr] (Weld Thread Pool -- 3)     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
17:17:53,619 ERROR [stderr] (Weld Thread Pool -- 3)     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
17:17:53,619 ERROR [stderr] (Weld Thread Pool -- 3)     at java.lang.Thread.run(Thread.java:748)
17:17:53,619 ERROR [stderr] (Weld Thread Pool -- 3)     at org.jboss.threads.JBossThread.run(JBossThread.java:485)

If I run the same code with a synchronous event, everything works fine.

So what am I missing?


Solution

  • I finally found the solution.

    Since the observer is asynchrounsly there is no container managed transaction available (which makes aboslutely sense, cause the transaction can't span around multiple threads). So I need to start a transaction on my own.

    Unfortunately this didn't work either. After hours of debugging I finally found the root cause, though. For some reason Wildfly's ContextManager threw an NPE because there was no class loader available in the observer class (ClassB). Fortunately there is already a bugfix available for the module wildfly-common. So I just upgraded from version 1.3.0.Final to 1.3.1.Final. The final code looks like this:

    @ApplicationScoped
    public class Observer {
    
        @Inject
        private Repository repository;
    
        public void onApplicationStarted(@ObservesAsync ApplicationStarted applicationStarted) throws Exception {
            UserTransaction userTransaction = (UserTransaction) new InitialContext().lookup("java:jboss/UserTransaction");
            userTransaction.begin();
            try {
                repository.getSomethingFromDatabase();
                // or repository.persistSomething();
            } catch (Exception e) {
                e.printStackTrace();
            }
            userTransaction.commit();
        }
    }