我不完全确定我理解了问题,但是它似乎是你希望限制哪些资源应该经过过滤器。为此,你可以简单地使用
名称绑定。
基本步骤:
Create a @NameBinding
annotation
@NameBinding
@Target({METHOD, TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Filtered {
}
Annotate the filter
@Filtered
@Provider
public class MyFilter implements ContainerRequestFilter {
Annotate whatever root resources, resource methods, sub resource classes you want to be filtered
更新
好的,经过一些尝试,我找到了几个解决方案...虽然都不太好看,但是能完成任务。
请记住,在DynamicFeature
中的configure
对于每个资源(方法)都会被调用。
算法1:
Get the method being checked and get its declaring class (in the case of a method in a sub resource, the declaring class will be the sub resource class)
Class<?> possibleSubResource =
resourceInfo.getResourceMethod().getDeclaringClass()
Build a temporary Resource
from your root resource
Resource resource = Resource.from(SomeResource.class)
Iterate its child resources, checking if it's a resource locator
for (Resource childResource : resource.getChildResources()) {
if (childResource.getResourceLocator() != null) {
If is is resource locator get the return type.
ResourceMethod sub = childResource.getResourceLocator();
Class responseClass = sub.getInvocable().getRawResponseType();
Then check if the response type from step 4 == the declaring class from step 1.
if (responseClass == possibleSubResource) {
context.register(SomeFilter.class);
}
为了使上述内容生效,实际上您需要从定位器方法中返回子资源类型,而不是
Resource
。(您可以尝试使用
Resource
来使其生效,但我还没有想出来)
@Path("{id}")
public SomeSubResource getSubResource() {
return new SomeSubResource();
}
以下是完整的代码,已经可运行(未经过实战测试 :-)
@Override
public void configure(ResourceInfo resourceInfo, FeatureContext context) {
Class<?> resourceClass = resourceInfo.getResourceClass();
if (resourceClass == SomeResource.class) {
context.register(SomeFilter.class);
}
Class<?> possibleSubResource = resourceInfo.getResourceMethod().getDeclaringClass();
Resource resource = Resource.from(SomeResource.class);
for (Resource childResource : resource.getChildResources()) {
if (childResource.getResourceLocator() != null) {
ResourceMethod sub = childResource.getResourceLocator();
Class responseClass = sub.getInvocable().getRawResponseType();
if (responseClass == possibleSubResource) {
context.register(SomeFilter.class);
}
}
}
}
算法2:
为了使其正常工作,我们建立的假设是:一个子资源的定义需要使用@Path
进行注释,并且没有任何Http方法的注释。
Get the method being checked and get its declaring class (in the case of a method in a sub resource, the declaring class will be the sub resource class)
Class<?> possibleSubResource =
resourceInfo.getResourceMethod().getDeclaringClass()
Iterate through the Method
s in the root resource class
for (Method method : SomeResource.class.getDeclaredMethods()) {
Check if the method has an Http method annotation
boolean isHttpPresent = false;
for (Class annot : Arrays.asList(GET.class, POST.class, PUT.class, DELETE.class)) {
if (method.isAnnotationPresent(annot)) {
isHttpPresent = true;
break;
}
}
Check if the method has the @Path
annotation. If it does, and it has not Http method annotations, then we register the filter
if (method.isAnnotationPresent(Path.class) && !isHttpPresent) {
Class subResourceClass = method.getReturnType();
if (subResourceClass == possibleSubResource) {
context.register(SomeFilter.class);
}
}
以下是完整的代码:
@Override
public void configure(ResourceInfo resourceInfo, FeatureContext context) {
Class<?> resourceClass = resourceInfo.getResourceClass();
if (resourceClass == SomeResource.class) {
context.register(SomeFilter.class);
}
Class<?> possibleSubResource = resourceInfo.getResourceMethod().getDeclaringClass();
for (Method method : SomeResource.class.getDeclaredMethods()) {
boolean isHttpPresent = false;
for(Class annot : Arrays.asList(GET.class,POST.class,PUT.class, DELETE.class)){
if (method.isAnnotationPresent(annot)) {
isHttpPresent = true;
break;
}
}
if(method.isAnnotationPresent(Path.class) && !isHttpPresent){
Class subResourceClass = method.getReturnType();
if (subResourceClass == possibleSubResource) {
context.register(SomeFilter.class);
}
}
}
}
再次强调,这些解决方案都没有经过实战验证,但是对我尝试过的少数情况有效。个人认为,只需使用名称绑定即可,但也许您可以向Jersey团队提出此问题。这(自动注册子资源时,根资源已被注册)似乎应该可以直接工作,或者至少可以进行配置。