Java EE 7 application is running on Wildfly 9.0.2.Final. There is a problem to access request scoped data from within @Asynchronous methods.
In web filter data (e.g. token) is set into RequestScoped CDI bean. Later we want to access this data. Everything works fine if we work in one thread. But if there is need to run code asynchronously the problem appears. CDI injects empty bean and request data is lost.
Here is the example:
@RequestScoped
public class CurrentUserService implements Serializable {
public String token;
}
@Stateless
public class Service {
@Inject
private RestClient client;
@Resource
private ManagedExecutorService executorService;
@Resource
private ContextService contextService;
@Asynchronous
private <T> Future<T> getFuture(Supplier<T> supplier) {
Callable<T> task = supplier::get;
Callable<T> callable = contextService.createContextualProxy(task, Callable.class);
return executorService.submit(callable);
}
public String getToken() throws Exception {
return getFuture(client::getToken).get();
}
}
@ApplicationScoped
public class RestClient {
@Inject
private CurrentUserService currentUserBean;
public String getToken() {
return currentUserBean.token;
}
}
In the given example we want to access current user token (CurrentUserService#token) from asynchronous Service.getToken method. As the result we will receive null.
It's expected that 'request scoped' data should be accessible from tasks executed within request scope. Something like InheritableThreadLocal should be used to allow assess to original thread data from new threads.
Is it a bug? May be I'm doing something wrong? If yes - what it the correct way to propagate such data into async calls?
Thanks in advance.
According to §2.3.2.1 of the Java EE Concurrency Utilities specification, you should not attempt to do this:
- Tasks that are submitted to a managed instance of ExecutorService may still be running after the lifecycle of the submitting component. Therefore, CDI beans with a scope of
@RequestScoped
,@SessionScoped
, or@ConversationScoped
are not recommended to use as tasks as it cannot be guaranteed that the tasks will complete before the CDI context is destroyed.
You need to collect your request scoped data and pass it to your asynchronous task when you create it, whether you use concurrency utilities or @Asynchronous methods.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With