1

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.
Community
  • 1
  • 1
Nilesh
  • 2,089
  • 3
  • 29
  • 53

1 Answers1

2

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:

Nilesh
  • 2,089
  • 3
  • 29
  • 53
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • I had hard time when I studied proxy in jersey documentation. Any hint, whats this code is doing behind the scene? – Nilesh Jan 13 '17 at 11:53
  • 1
    `proxy` cause a dynamic proxy to be created. So every time you access the service, it will be a proxy. the `proxyForSameScope` just says that if the parent is in the same scope, i.e a request scope, don't make it a proxy, just use the real object. For instance, now it will be a proxy object, but if you try to inject it into a resource class (which is request scope by default), it will the the actual instance. – Paul Samsotha Jan 13 '17 at 12:05
  • The article I linked to explains this more. And there is also a linked article in _that_ article about dynamic proxies. That might be a good read also, if you care to learn how the proxies work behind the scenes. – Paul Samsotha Jan 13 '17 at 12:06
  • The proxies really don't do much at runtime other than look up the requested service whenever a method of the service is invoked. This allows for scopes with different lifecycles to be changed even if the object injected into the service (the proxy) does not change – jwells131313 Jan 13 '17 at 17:43
  • The solution is correct. But unfortunately it failed in my case due to completely unrelated reason. Its because ```java.lang.InstantiationException: javax.crypto.Cipher_$$_jvstffc_0``` That means, there is nothing like new Cipher(). Hence I had to wrap the Cipher into CipherBox and its done. – Nilesh Jan 17 '17 at 10:47
  • Thanks for linking the article, it linked to this [article](https://psamsotha.github.io/jersey/2015/12/16/dynamic-proxies-dependency-injection.html) which helped me to understand proxy. – Nilesh Jan 17 '17 at 10:50
  • I have modified the question title to accept this answer. With your permission, should I modify the answer to add that **Cipher cant be proxied, add a wrapper around it** or should I write another answer to help the others. – Nilesh Jan 17 '17 at 13:47
  • It's up to you. I don't mind if you want to modify it. – Paul Samsotha Jan 17 '17 at 13:53