I am currently refactoring a Jersey Web App and want to bundle some cross cutting concerns in their own classes and use annotations to intercept methods. For example there are a lot of methods where I need to check if the user is the owner of the entity he wants to alter (in my case this is a project). Therefor within the interceptor I need to make database calls and though having the appropriate DAOs injected would be the best way to go.
Currently my interceptor looks like this:
public class ProjectOwnerCheckInterceptor implements MethodInterceptor {
@Inject
private EntityManager em;
@Inject
private UserProvider userProvider;
@Inject
private RMUserDAO rmUserDAO;
@Inject
private ProjectDAO projectDAO;
public ProjectOwnerCheckInterceptor() {
// TODO Auto-generated constructor stub
}
@Override
public Object invoke(MethodInvocation arg0) throws Throwable {
// First of all let's get the annotation
ProjectOwnerCheck check = arg0.getMethod().getAnnotation(ProjectOwnerCheck.class);
// if there is no check, then just proceed!
if (check == null)
arg0.proceed();
long projectId = (long) arg0.getArguments() [check.projectIdIndex()];
// Handling ownership!!
Project project = getProjectOrThrow(projectId);
return arg0.proceed();
}
}
The custom annotation is straight forward. I need to add some little information which argument position the entityId in the method has to check is as number of parameters and types vary:
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
public @interface ProjectOwnerCheck {
int projectIdIndex() default -1;
}
For Jersey/HK2 to know what to do with the interceptors I have created a filter implementing InterceptionService:
public class HK2InterceptorFilter implements InterceptionService {
private final static MethodInterceptor PROJECT_CHECK_METHOD_INTERCEPTOR = new ProjectOwnerCheckInterceptor();
private final static List<MethodInterceptor> PROJECT_CHECK_METHOD_LIST = Collections
.singletonList(PROJECT_CHECK_METHOD_INTERCEPTOR);
public HK2InterceptorFilter() {
// TODO Auto-generated constructor stub
}
@Override
public Filter getDescriptorFilter() {
return BuilderHelper.allFilter();
}
@Override
public List<MethodInterceptor> getMethodInterceptors(Method method) {
if (method.isAnnotationPresent(ProjectOwnerCheck.class))
return PROJECT_CHECK_METHOD_LIST;
return null;
}
@Override
public List<ConstructorInterceptor> getConstructorInterceptors(Constructor<?> constructor) {
// TODO Auto-generated method stub
return null;
}
}
I am binding that Filter in my JerseyApplication class:
register(new AbstractBinder() {
@Override
protected void configure() {
try {
bind(HK2InterceptorFilter.class).to(InterceptionService.class).in(Singleton.class);
bind(getPasswordStorage()).to(PasswordStorage.class);
bind(getDocumentService()).to(DocumentService.class);
bind(UserManagementAccessor.getUserProvider()).to(UserProvider.class);
} catch (Exception e) {
throw new InternalServerErrorException(e);
}
}
});
When set a breakpoint in my interceptor I can see that it is correctly instantiated and the method gots called. But what I totally miss are all those @Inject fields I need to have to make my check. Am I missing something or is this in HK2 not possible. I used to work with Guice and there it is working (I am - due to the fact the app's code base is quite large, but time limited - bound to HK2:) ).
Thanks for all your help in advance!
PS:
I am using Jersey 2.17