I recently solved this exact problem. There are a few things you can do. First, read ServletScopes.continueRequest()which wraps the caller so that it runs as if it were in the current request. However, this is not a complete solution, because it will not forward objects @RequestScoped, but only basic things, such as HttpServletResponse. This is because objects @RequestScopedshould not be thread safe. You have several options:
If your whole hierarchy @RequestScopedcan only be calculated from an HTTP response, you're done! However, you will get new instances of these objects in another thread.
, RequestScoped, , .
@RequestScoped , , . , @ThreadSafeRequestScoped .
:
public class RequestScopePropagator {
private final Map<Key<?>, Provider<?>> requestScopedValues = new HashMap<>();
@Inject
RequestScopePropagator(Injector injector) {
for (Map.Entry<Key<?>, Binding<?>> entry : injector.getAllBindings().entrySet()) {
Key<?> key = entry.getKey();
Binding<?> binding = entry.getValue();
if (binding.acceptScopingVisitor(IS_REQUEST_SCOPED)) {
requestScopedValues.put(key, binding.getProvider());
}
}
}
private final BindingScopingVisitor<Boolean> IS_REQUEST_SCOPED = new BindingScopingVisitor<Boolean>() {
@Override
public Boolean visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation) {
return scopeAnnotation == RequestScoped.class;
}
@Override
public Boolean visitScope(Scope scope) {
return scope == ServletScopes.REQUEST;
}
@Override
public Boolean visitNoScoping() {
return false;
}
@Override
public Boolean visitEagerSingleton() {
return false;
}
};
public <T> Callable<T> continueRequest(Callable<T> callable) {
Map<Key<?>, Object> seedMap = new HashMap<>();
for (Map.Entry<Key<?>, Provider<?>> entry : requestScopedValues.entrySet()) {
seedMap.put(entry.getKey(), entry.getValue().get());
}
return ServletScopes.continueRequest(callable, seedMap);
}
}