The jersey interceptors are constructed at the the time of application startup. Hence its dependencies(Ciphers in this case) are injected out of Request Scope.
The problem is that Ciphers are stateful so they should be injected in the Request Scope. How to do that ?
@Provider
@Priority(Priorities.ENTITY_CODER + 1)
public class CryptInterceptor implements ReaderInterceptor, WriterInterceptor {
@Inject @Named("ENC_CIPHER")
private Cipher encryptionCipher;
@Inject @Named("DEC_CIPHER")
private Cipher decryptionCipher;
@Override
public Object aroundReadFrom(ReaderInterceptorContext context) throws IOException, WebApplicationException {
InputStream inputStream = context.getInputStream();
CipherInputStream cipherInputStream = new CipherInputStream(inputStream, decryptionCipher);
context.setInputStream(cipherInputStream);
return context.proceed();
}
@Override
public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
OutputStream outputStream = context.getOutputStream();
CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, encryptionCipher);
context.setOutputStream(cipherOutputStream);
context.proceed();
}
}
Expecting new Cipher for each new request is like injecting them in RequestScope --
public class BootstrapBinder extends AbstractBinder {
@Override
protected void configure() {
bindFactory(EncCipherFactory.class).to(Cipher.class).named("ENC_CIPHER").in(RequestScoped.class);
bindFactory(DecCipherFactory.class).to(Cipher.class).named("DEC_CIPHER").in(RequestScoped.class);
}
}
Now obviously hk2(DI of jersey) cant inject RequestScoped object inside Singleton interceptor. It causes :
java.lang.IllegalStateException: Not inside a request scope.
You need to proxy the services. If you don't then Jersey will try to inject the actual object, and there is no request when the interceptor is created. As far as trying to make the interceptor itself request scoped, I don't know. Not sure if it's possible.
bindFactory(EncCipherFactory.class)
.proxy(true)
.proxyForSameScope(false)
.to(Cipher.class)
.named("ENC_CIPHER")
.in(RequestScoped.class);
Do the same with the other one also. But keep in mind that it will be a proxy instance when you access it, not the cipher instance.
See Also: