Search code examples
javajerseyjax-rsjersey-2.0hk2

How to use RequestScoped objects within singleton jersey interceptor?


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.

Solution

  • 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: