6

I've looked at other questions relating to this error on the site but most of them are either about SessionScope or are unanswered. The only possibly helpful one is No active contexts for scope type javax.enterprise.context.RequestScoped when invoking a bean from a thread but it's not in the context I have.

I'm running a JAX-RS endpoint on Wildfly 10.1 (Java ee 7). Looks something like this:

@Path("")
public class ServerResource {

    @Inject
    Order order;

    @Resource
    ManagedExecutorService mes;

    @PUT
    @Path("/prepareOrder")
    public void prepareOrder(@Suspended AsyncResponse response) {
        mes.execute(() ->  {
            try {
                Item item = new Item(); // JPA entity
                order.setItem(item); // line 71
                // call a service to save the order data (like item) to the DB
            } catch (Exception e) {
                e.printStackTrace();
                response.resume(false);
            }
            response.resume(true);
        });
    }
}

I added the try-catch only because of this problem, it's not generally there. Order is

@Stateful
@RequestScoped
public class Order {
    private Item item;
    // setter and getter
}

Order is RequestScoped because when it's being used/processed it goes through a sort of chain of responsibility (several Stateless beans that inject the Order and change it in sequence). Anyway the question is not about the design but about the error.

The line order.setItem(item); throws the exception:

org.jboss.weld.context.ContextNotActiveException: WELD-001303: No active contexts for scope type javax.enterprise.context.RequestScoped
at org.jboss.weld.manager.BeanManagerImpl.getContext(BeanManagerImpl.java:689)
at org.jboss.weld.bean.ContextualInstanceStrategy$DefaultContextualInstanceStrategy.getIfExists(ContextualInstanceStrategy.java:90)
at org.jboss.weld.bean.ContextualInstanceStrategy$CachingContextualInstanceStrategy.getIfExists(ContextualInstanceStrategy.java:165)
at org.jboss.weld.bean.ContextualInstance.getIfExists(ContextualInstance.java:63)
at org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:83)
at org.jboss.weld.bean.proxy.ProxyMethodHandler.getInstance(ProxyMethodHandler.java:125)
at com.a.b.Order$Proxy$_$$_WeldClientProxy.setItem(Unknown Source)
at com.a.c.ServerResource.lambda$0(ServerResource.java:71)
at org.jboss.as.ee.concurrent.ControlPointUtils$ControlledRunnable.run(ControlPointUtils.java:105)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at org.glassfish.enterprise.concurrent.internal.ManagedFutureTask.run(ManagedFutureTask.java:141)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
at org.glassfish.enterprise.concurrent.ManagedThreadFactoryImpl$ManagedThread.run(ManagedThreadFactoryImpl.java:250)

I tried to annotate the ServerResource class with @Stateless or RequestScope (@Stateless vs @RequestScoped) but it didn't matter.

Why do I get this error and how do I get my code working?

Kukeltje
  • 12,223
  • 4
  • 24
  • 47
Mark
  • 2,167
  • 4
  • 32
  • 64
  • Not sure about this but is mixing CDI annotation (`RequestScoped`) and EJB annotation (`Stateless` / `Stateful`) necessary? Maybe your `Order` can solely be a `CDI bean` or a `EJB bean` depend on your design – Al-un Oct 02 '17 at 16:54
  • @Al1 I removed `@Stateful` and there's no difference. – Mark Oct 02 '17 at 18:33
  • 4
    It's because the request is tied to the server thread processing the request. When you switch threads, there is no longer access to that request context. So you can't access something that is "request scoped" from a different thread. – Paul Samsotha Oct 02 '17 at 23:04
  • @peeskillet so it would work with a synchronous response right? How can i make it work with the asynch way? – Mark Oct 02 '17 at 23:10
  • @peeskillet I don't understand how this helps. I have stateless beans, like the service that handles persistence that require the Order object of that request. How would using a singleton solve the problem? – Mark Oct 02 '17 at 23:22
  • @peeskillet found https://stackoverflow.com/questions/23732089/how-to-enable-request-scope-in-async-task-executor but it's for spring. – Mark Oct 02 '17 at 23:27

2 Answers2

9

In CDI, contexts do not propagate to other threads and if you glance at spec, there are scattered notions of contexts being tied to thread. And the Bean stores ("maps" which hold beans for context) are implemented by ThreadLocal so it just won't work.

There is no way around this using existing contexts - the only option is to define your custom scope/context which will handle context propagation across threads.

EDIT: Note that there is now a JIRA ticket created which considers adding something like this functionality to Weld.

Siliarus
  • 6,393
  • 1
  • 14
  • 30
0

You can join the context but I think you understand it wrong. The server has it's own thread pool. Therefore each request is by default asynchronous (Every user request create new thread).

ContextControl ctxCtrl = (ContextControl) BeanProvider.getContextualReference(ContextControl.class, new Annotation[0]);
ctxCtrl.startContext(RequestScoped.class);
try{
//...
} finally {
 ctxCtrl.stopContext(RequestScoped.class);
}
Milkmaid
  • 1,659
  • 4
  • 26
  • 39
  • If the request is synchronous there's no problem with the RequestScope, so what am I understanding wrong? – Mark Oct 04 '17 at 09:25
  • There is not a single reason to create that request asynchronously. Because it does not block other requests by default. – Milkmaid Oct 05 '17 at 04:53