将Jersey 2.25与@NamedBinding子资源方法一起使用不会调用过滤器。
在下面的代码中,getData()方法触发AuthorizationFilter,但getSubDetails()方法不会触发。
@NameBinding
@Retention(RUNTIME)
@Target({ TYPE, METHOD })
public @interface Secured {
Permission[] value() default {};
}
@Secured
@Provider
@Priority(Priorities.AUTHORIZATION)
public class AuthorizationFilter implements ContainerRequestFilter {
...
}
@Produces(MediaType.APPLICATION_JSON)
@Path("api/v1/jobs/{jobId}/document-sources")
@Secured(Permission.JOB_READER)
public class MyEndpoint {
@Path("/{subId}")
@GET
@Secured(Permission.READ)
public Class<?> getData(@PathParam("subId") String subId){
return "data";
}
@Path("/{subId}/details")
@Secured(Permission.READ)
public Class<?> getSubDetails(@PathParam("subId") String subId){
return SubDetails.class;
}
}
JAX-RS文档(https://docs.oracle.com/javaee/7/api/javax/ws/rs/container/ContainerRequestFilter.html)似乎暗示该过滤器应在子资源上运行。
难道我做错了什么? NameBinding筛选器不再适用于子资源方法吗?
最佳答案
对于遇到此问题的其他人:
子资源定位器方法没有针对它们运行的NameBinding过滤器(至少在Jersey中)。我找不到任何说明这是否正确的文档。
在我们的例子中,过滤器很重要,因为它正在向请求上下文添加对象,定位器方法使用这些对象来确定要返回的子资源。这些对象的创建有些昂贵(涉及数据库调用),因此我们不想只在子资源定位器方法中复制对象创建代码(另外还会违反DRY)。
我最后想到的解决方案是将对象创建逻辑移到Factory中,并让Factory使用请求上下文缓存来确保它仅一次完成对象初始化。然后,将工厂用于过滤器(用于授权)和子资源方法(用于确定要发送哪个子资源)。然后,每个子资源都必须具有授权过滤器注释。