簡體   English   中英

Jersey中過濾器的動態綁定不適用於子資源

[英]Dynamic binding of a filter in Jersey doesn't work for sub-resources

我創建了一個澤西過濾器,我需要將它分配給一些資源(不是全部)。 因此,我正在使用動態綁定來實現這一點。

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);
    }   
}

即使澤西文件聲稱

configure方法將針對應用程序中定義的每個資源方法執行一次。

上面顯示的MyDynamicFeature中的configure方法根本沒有調用MyResource類的getSubResource方法。 它確實被調用MyResource類中的所有其余方法(我在示例中省略了)。

有沒有辦法讓這項工作適用於子資源? 我也需要將我的過濾器應用於MySubResource

我們使用Jersey 2.21。

看看這個問題 我不確定它目前是否可行。 如果在功能中添加一些日志記錄以記錄方法和類,您將看到永遠不會遍歷子資源方法。 正如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"; }
    }
}

上面將綁定V2Resource所有資源方法以及V2SubResource

以下是使用Jersey Test Framework的完整示例。 像任何其他JUnit測試一樣運行它

更新 :請注意,使用以下測試,使用Jersey的當前(2.26)版本,版本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"));
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM