In my Jersey application, I'd like to have a ContainerRequestContext
instance injected into various objects. In the case that the object in being created outside of the context of a request, I would like null to be injected.
I noticed HK2 has an @Optional
annotation that you can annotate dependencies with, and I was hoping that would do the job for, unfortunately it doesn't change the behaviour at all.
public class MyObject {
private final ContainerRequestContext containerRequestContext;
@Inject
public MyObject(@Optional ContainerRequestContext containerRequestContext) {
this.containerRequestContext = containerRequestContext;
}
}
If this object is instantiated outside of a request scope (in my case, a Job run by a Quartz scheduler), then an exception like this gets thrown:
java.lang.IllegalStateException: Not inside a request scope.
It would massively simplify my code if Jersey would just inject null when outside of a request scope, any ideas how to do this?
I've figured out a way of doing it, but it's basically a hack. Instead of having ContainerRequestContext
injected, you can instead try to explicitly get a ContainerRequestContext
instance from the ServiceLocator
, and handle the exception when the context is outside of a request scope.
public class MyObject {
private final Optional<ContainerRequestContext> containerRequestContext;
@Inject
public MyObject(ServiceLocator serviceLocator) {
this.containerRequestContext = getContainerRequestContext(serviceLocator);
}
private Optional<ContainerRequestContext> getContainerRequestContext(ServiceLocator serviceLocator) {
try {
return Optional.of(serviceLocator.getService(ContainerRequestContext.class));
} catch (MultiException e) {
if (e.getCause() instanceof IllegalStateException) {
return Optional.empty();
} else {
throw new ExceptionInInitializerError(e);
}
}
}
}
It's then possible to go one step further and create your own OptionalContainerRequestContext
type.
public class OptionalContainerRequestContext {
private final Optional<ContainerRequestContext> containerRequestContext;
@Inject
public OptionalContainerRequestContext(ServiceLocator serviceLocator) {
this.containerRequestContext = getContainerRequestContext(serviceLocator);
}
public ContainerRequestContext get() {
return containerRequestContext.get();
}
public boolean isPresent() {
return containerRequestContext.isPresent();
}
private Optional<ContainerRequestContext> getContainerRequestContext(ServiceLocator serviceLocator) {
try {
return Optional.of(serviceLocator.getService(ContainerRequestContext.class));
} catch (MultiException e) {
if (e.getCause() instanceof IllegalStateException) {
return Optional.empty();
} else {
throw new ExceptionInInitializerError(e);
}
}
}
}
You can then bind it:
bind(OptionalContainerRequestContext.class).to(OptionalContainerRequestContext.class);
And then inject it wherever you need:
public class MyObject {
private final OptionalContainerRequestContext optionalContainerRequestContext;
@Inject
public MyObject(OptionalContainerRequestContext optionalContainerRequestContext) {
this.optionalContainerRequestContext = optionalContainerRequestContext;
}
}