我创建了一个 Jersey 过滤器,我需要将其分配给某些资源(不是全部)。因此,我使用动态绑定(bind)来实现这一点。
public class MyDynamicFeature implements DynamicFeature {
@Override
public void configure(ResourceInfo resourceInfo, FeatureContext featureContext) {
Path resourcePath = resourceInfo.getResourceClass().getAnnotation(Path.class);
if (resourcePath != null && resourcePath.value().contains("/v2/"))
{
featureContext.register(MyFilter.class);
}
}
}
因此,我希望将此过滤器应用于那些路径中包含特定字符串的资源中的所有方法。其中一些资源使用子资源定位符来定义子资源。例如,
@Path("/v2/resource_path")
@Consumes({ ... })
@Produces({ ... })
class MyResource
{
@Path("/subresource_path")
public MySubResource getSubResource(@Context ResourceContext rc)
{
return rc.getResource(MySubResource.class);
}
}
尽管 Jersey 文档声称
The configure method will be executed once for each resource method that is defined in the application.
上面显示的 MyDynamicFeature
中的 configure
方法根本不会被 MyResource
类的 getSubResource
方法调用。不过,它确实会被 MyResource
类中的所有其余方法调用(我在示例中省略了)。
有没有办法让这个工作适用于子资源?我还需要将过滤器应用于 MySubResource
。
我们使用 Jersey 2.21。
最佳答案
查看this issue 。我不确定目前是否可能。如果您在功能中添加一些日志记录来记录方法和类,您将看到子资源方法永远不会被遍历。正如 Marek 在该问题中所解释的那样,这是因为为了处理这个问题,需要调用子资源定位器方法,但事实并非如此。
唯一的解决方法是使用 Name Binding
反而。我已经对此进行了测试并且它有效(见下文)。这个想法是制作一个自定义注释,并注释您想要过滤的过滤器、资源类和子资源类。例如
@NameBinding
@Target({METHOD, TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SomeAnno {}
@SomeAnno
public class Filter implements ContainerRequestFilter {}
@SomeAnno
@Path("v2")
public class V2Resource {
@Path("sub")
public V2SubResource get() {
return new V2SubResource();
}
@SomeAnno
public static class V2SubResource {
@GET
public String get() { return "get"; }
}
}
上面将绑定(bind) V2Resource
以及 V2SubResource
中的所有资源方法。
下面是使用 Jersey Test Framework 的完整示例。像任何其他 JUnit 测试一样运行它
更新:请注意,在以下测试中,对于当前 (2.26) 版本的 Jersey,版本 2 资源的测试会因过滤器中返回 1000 状态代码而挂起。我猜泽西不喜欢这样。要解决此问题,只需将过滤器中的状态代码更改为 500 并相应地修复测试断言以测试 500 状态代码。
import java.io.IOException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.logging.Logger;
import javax.ws.rs.GET;
import javax.ws.rs.NameBinding;
import javax.ws.rs.Path;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
import org.glassfish.jersey.filter.LoggingFilter;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.ServerProperties;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
/**
* Stack Overflow question http://stackoverflow.com/q/36878817/2587435
*
* Run this like any other JUnit test. Only one required test dependency
*
* <dependency>
* <groupId>org.glassfish.jersey.test-framework.providers</groupId>
* <artifactId>jersey-test-framework-provider-inmemory</artifactId>
* <version>${jersey2.version}</version>
* </dependency>
*
* @author Paul Samsotha
*/
public class DynamicSubresourceTest extends JerseyTest {
@NameBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public static @interface Status1000 {}
@Provider
@Status1000
public static class Status1000Filter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext context) throws IOException {
context.abortWith(Response.status(500).build());
}
}
@Path("v1")
public static class V1Resource {
@GET
public String get() {
return "v1";
}
@Path("sub")
public V1SubResource getSub() {
return new V1SubResource();
}
public static class V1SubResource {
@GET
public String get() {
return "v1subresource";
}
}
}
@Path("v2")
@Status1000
public static class V2Resource {
@GET
public String get() {
return "v2";
}
@Path("sub")
public V2SubResource getSub() {
return new V2SubResource();
}
@Status1000
public static class V2SubResource {
@GET
public String get() {
return "v2subresource";
}
}
}
@Override
public ResourceConfig configure() {
return new ResourceConfig(V1Resource.class, V2Resource.class)
.property(ServerProperties.WADL_FEATURE_DISABLE, true)
.register(Status1000Filter.class)
.register(new LoggingFilter(Logger.getAnonymousLogger(), true));
}
@Test
public void should_return_1000_for_v2_resource_method() {
final Response response = target("v2").request().get();
assertThat(response.getStatus(), is(500));
}
@Test
public void should_return_1000_for_v2_subresource_locator() {
final Response response = target("v2/sub").request().get();
assertThat(response.getStatus(), is(500));
}
@Test
public void should_return_data_for_v1_resource_method() {
final Response response = target("v1").request().get();
assertThat(response.getStatus(), is(200));
assertThat(response.readEntity(String.class), is("v1"));
}
@Test
public void should_return_data_for_v1_subresource_locator() {
final Response response = target("v1/sub").request().get();
assertThat(response.getStatus(), is(200));
assertThat(response.readEntity(String.class), is("v1subresource"));
}
}
关于java - Jersey 中过滤器的动态绑定(bind)不适用于子资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36878817/