Reputation: 13471
I'm using Jax-rs, and I'm doing some logic in the Filters
, and then I would like to share information between ContainerRequestFilter
(Filter) and ReaderInterceptor
(Interceptor).
I can see that between Filters and Interceptors is possible through the set/getProperties
but between Filter and Interceptors is not possible.
Any idea if there's any other mechanism?.
Regards.
Upvotes: 1
Views: 758
Reputation: 209072
So any easier way than using a separate service for this is to simply inject the ContainerRequestContext
into the ReaderInterceptor
. We need to inject it as a javax.inject.Provider
so that we can lazy retrieve it. If we don't do this, we will run into scoping issues, as the interceptor is inherently a singleton and the request context is request scoped (meaning a new one is created for each request).
public static class MyInterceptor implements ReaderInterceptor {
private final javax.inject.Provider<ContainerRequestContext> requestProvider;
@Inject
public MyInterceptor(javax.inject.Provider<ContainerRequestContext> requestProvider) {
this.requestProvider = requestProvider;
}
@Override
public Object aroundReadFrom(ReaderInterceptorContext readerInterceptorContext) throws IOException, WebApplicationException {
ContainerRequestContext request = requestProvider.get();
String prop = (String) request.getProperty("SomeProp");
}
}
With the javax.inject.Provider
, we get the actual service by calling get()
. Because we are using Provider
, the service will be retrieved from a request scoped context, meaning that the instance will be tied to the request.
1. See Request Scoped Injection into a Singleton with Jersey for more information.
Upvotes: 1
Reputation: 209072
You can use a request scoped service that you inject into both the filter and the interceptor. For instance
public interface RequestScopedService {
void setSomething(Object something);
Object getSomething();
}
public class RequestScopedServiceImpl implements RequestScopedService {
@Override
public void setSomething(Object something) {}
@Override
public Object getSomething() {}
}
It's best practice to use interfaces, that's why I did that here. To configure it, you register an AbstractBinder
with your ResourceConfig
1.
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(new AbstractBinder() {
@Override
public void configure() {
bind(RequestScopedServiceImpl.class)
.to(RequestScopedService.class)
.proxy(true)
.proxyForSameScope(false)
.in(RequestScoped.class);
}
});
}
}
Now you can inject it into both the filter and the interceptor.
public class MyFilter implements ContainerRequestFilter {
private final RequestScopedService service;
@Inject
public MyFilter(RequestScopedService service) {
this.service = service;
}
}
public class MyInterceptor implements ReaderInterceptor {
private final RequestScopedService service;
@Inject
public MyInterceptor(RequestScopedService service) {
this.service = service;
}
}
We use the proxy()
method to configure it because the service is a request scoped service (meaning a new one is created for each request) and the filter and writer interceptor are singletons. So we need it to be a proxy that forwards calls to the real service under the hood 2.
1. If you are not using a ResourceConfig
for your configuration (maybe you are using web.xml), see both my answer in "Dependency Injection with Jersey 2.0 and What exactly is the ResourceConfig class in Jersey 2?.
2. You can learn some more about this in this article
Upvotes: 1