2016-04-27 8 views
1

Ich erstellte einen Jersey-Filter und ich brauche es einige Ressourcen zugewiesen (nicht alle). Daher verwende ich dynamische Bindung, um das zu erreichen.Dynamische Bindung eines Filters in Jersey funktioniert nicht für Sub-Ressourcen

Also ich möchte diesen Filter auf alle Methoden in diesen Ressourcen angewendet werden, die eine bestimmte Zeichenfolge in ihren Pfaden enthalten. Einige dieser Ressourcen verwenden Sub-Resource Locators, um Subressourcen zu definieren. Z. B.

@Path("/v2/resource_path") 
@Consumes({ ... }) 
@Produces({ ... }) 
class MyResource 
{ 
    @Path("/subresource_path") 
    public MySubResource getSubResource(@Context ResourceContext rc) 
    { 
     return rc.getResource(MySubResource.class); 
    } 
} 

Obwohl Dokumentation Jersey behauptet

Das configure Verfahren wird einmal für jede Ressource-Methode ausgeführt werden, die in der Anwendung definiert ist.

die configure Methode in MyDynamicFeature oben für getSubResource Methode der MyResource Klasse nicht gezeigt nicht bekommen überhaupt bezeichnet. Es wird jedoch für alle anderen Methoden in der Klasse MyResource aufgerufen (die ich im Beispiel weggelassen habe).

Gibt es eine Möglichkeit, dies für Sub-Ressourcen funktionieren zu lassen? Ich muss meinen Filter auch auf MySubResource anwenden.

Wir verwenden Jersey 2.21.

+0

Becuase der '@ Path' für' getSubResource' ist '/ subresource_path' und daher nicht enthält' v2' –

Antwort

0

Auschecken this issue. Ich bin mir nicht sicher, ob das momentan möglich ist. Wenn Sie eine Protokollierung Ihrer Funktion hinzufügen, um die Methode und die Klasse zu protokollieren, werden Sie sehen, dass die Methoden der Unterressourcen nie durchlaufen werden. Wie von Marek in der Ausgabe erklärt, ist es, weil, um damit umzugehen, die Sub-Ressource-Locator-Methode aufgerufen werden müsste, was es nie ist.

Die einzige Problemumgehung besteht darin, stattdessen Name Binding zu verwenden. Ich habe das getestet und es funktioniert (siehe unten). Die Idee besteht darin, eine benutzerdefinierte Annotation zu erstellen und den Filter, die Ressourcenklasse und die Sub-Ressourcenklasse, die gefiltert werden sollen, mit Anmerkungen zu versehen. Zum Beispiel

@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"; } 
    } 
} 

Die obige binden würde, die alle Ressourcen Methoden in V2Resource sowie V2SubResource.

Unten finden Sie ein vollständiges Beispiel mit Jersey Test Framework. Führen Sie es wie jedes andere JUnit-Test

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(1000).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(1000)); 
    } 

    @Test 
    public void should_return_1000_for_v2_subresource_locator() { 
     final Response response = target("v2/sub").request().get(); 
     assertThat(response.getStatus(), is(1000)); 
    } 

    @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")); 
    } 
} 
+0

Danke, @peeskillet. Dies beantwortet meine Frage. –

+0

Leider ist die Namensbindung für uns nicht geeignet, da dieser Filter ** für eine Gruppe von aktuellen und zukünftigen Ressourcen ** erforderlich ist. Daher kann ich nicht erwarten, dass Entwickler zukünftige Ressourcen schreiben, um diese Ressourcen und Unterressourcen zu kennen/zu merken und zu kommentieren. Daher wird es mit einem globalen Filter gehen, der eine Überprüfung innerhalb der 'filter' Methode hat, um Ressourcen auszuschließen, die diesen Filter nicht benötigen. Dies ist eine weniger wünschenswerte Lösung, da die Prüfbedingung bei jeder Anforderung ausgeführt wird. –

Verwandte Themen