将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使用请求上下文缓存来确保它仅一次完成对象初始化。然后,将工厂用于过滤器(用于授权)和子资源方法(用于确定要发送哪个子资源)。然后,每个子资源都必须具有授权过滤器注释。

09-25 22:01