Jersey / Jax-RS: how to filter resources and sub-resources

In Jersey-2, how can I bind a filter to all methods of a resource, as well as to all methods of its sub-resources?

For example, if I have the following 2 resources:

import javax.inject.Singleton;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.glassfish.jersey.server.model.Resource;

@Path("/myresource/{id: \\d+}")
@Produces(MediaType.APPLICATION_JSON)
@Singleton
class RootResource {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response get(@PathParam("id") Long id) {
        return Response.ok().build();
    }

    @Path("/sub")
    public Resource getSubResource() {
        return Resource.from(SubResource.class);
    }
}

@Produces(MediaType.APPLICATION_JSON)
@Singleton
class SubResource {
    @GET
    @Path("/{subid: \\d+}")
    public Response get(@PathParam("id") Long id, @PathParam("subid") Long subid) {
        return Response.ok().build();
    }
}

I would like to filter RootResource.get(Long)and SubResource.get(Long, Long). But if I have other resources, they should not be filtered.

Using DynamicFeature, we have only information about the class and method.

import javax.ws.rs.container.DynamicFeature;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.FeatureContext;

public class MyFeature implements DynamicFeature {

    @Override
    public void configure(ResourceInfo resourceInfo, FeatureContext context) {
        // Here how can I find out that SubResource is actually a sub-resource of RootResource
    }

}

The idea is that I want to be able to filter out all calls for a specific set of id (the set of identifiers is dynamic), with something more or less the following:

import java.io.IOException;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;


public class MyFilter implements ContainerRequestFilter {

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        for(Object resource:requestContext.getUriInfo().getMatchedResources()) {
            if(resource instanceof RootResource) {
                Long id = Long.valueOf(requestContext.getUriInfo().getPathParameters().getFirst("id"));
                // ...
            }
        }
    }

}

but I would like to avoid finding suitable resources. Is it possible?

+4
2

100%, , , , . .

:

  • @NameBinding

    @NameBinding 
    @Target({METHOD, TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Filtered {    
    }
    
  • @Filtered
    @Provider
    public class MyFilter implements ContainerRequestFilter {
    
  • , , , .


UPDATE

, . Netiher , .

, configure DynamicFeature (), .

1:

  • ( )

    Class<?> possibleSubResource =
             resourceInfo.getResourceMethod().getDeclaringClass();
    
  • Resource

    Resource resource = Resource.from(SomeResource.class);
    
  • , ,

    for (Resource childResource : resource.getChildResources()) {
        if (childResource.getResourceLocator() != null) {
    
  • , .

    ResourceMethod sub = childResource.getResourceLocator();
    Class responseClass = sub.getInvocable().getRawResponseType();
    
  • , 4 == 1.

    if (responseClass == possibleSubResource) {
        context.register(SomeFilter.class);
    }
    

Resource. ( Resource, )

@Path("{id}")
public SomeSubResource getSubResource() {
    return new SomeSubResource();
}

, ( : -)

@Override
public void configure(ResourceInfo resourceInfo, FeatureContext context) {
    Class<?> resourceClass = resourceInfo.getResourceClass();

    if (resourceClass == SomeResource.class) {
        context.register(SomeFilter.class);
    }

    Class<?> possibleSubResource = resourceInfo.getResourceMethod().getDeclaringClass();

    Resource resource = Resource.from(SomeResource.class);
    for (Resource childResource : resource.getChildResources()) {
        if (childResource.getResourceLocator() != null) {
            ResourceMethod sub = childResource.getResourceLocator();
            Class responseClass = sub.getInvocable().getRawResponseType();

            if (responseClass == possibleSubResource) {
                context.register(SomeFilter.class);
            }
        }
    }
}

2:

, , , Sub Resource, , @Path Http

  • ( )

    Class<?> possibleSubResource =
             resourceInfo.getResourceMethod().getDeclaringClass();
    
  • Method

    for (Method method : SomeResource.class.getDeclaredMethods()) {
    
  • , Http

    boolean isHttpPresent = false;
    for (Class annot : Arrays.asList(GET.class, POST.class, PUT.class, DELETE.class)) {
        if (method.isAnnotationPresent(annot)) {
            isHttpPresent = true;
            break;
        }
    }
    
  • , @Path. , Http-,

    if (method.isAnnotationPresent(Path.class) && !isHttpPresent) {
        Class subResourceClass = method.getReturnType();
        if (subResourceClass == possibleSubResource) {
            context.register(SomeFilter.class);
        }
    }
    

@Override
public void configure(ResourceInfo resourceInfo, FeatureContext context) {
    Class<?> resourceClass = resourceInfo.getResourceClass();

    if (resourceClass == SomeResource.class) {
        context.register(SomeFilter.class);
    }

    Class<?> possibleSubResource = resourceInfo.getResourceMethod().getDeclaringClass();

    for (Method method : SomeResource.class.getDeclaredMethods()) {
        boolean isHttpPresent = false;
        for(Class annot : Arrays.asList(GET.class,POST.class,PUT.class, DELETE.class)){
            if (method.isAnnotationPresent(annot)) {
                isHttpPresent = true;
                break;
            }
        }
        if(method.isAnnotationPresent(Path.class) && !isHttpPresent){
            Class subResourceClass = method.getReturnType();
            if (subResourceClass == possibleSubResource) {
                context.register(SomeFilter.class);
            }
        }
    }
}

, , , . , , , , . ( , ) , , , .

+5

: , - :

@Path("/api/sample")
@Produces(MediaType.APPLICATION_JSON)
public class SampleResource {

    @Path("/filtered")
    @GET
    @Sample(value = "a sample value")
    public Hello filtered() {
        return new Hello("filtered hello");
    }

    @Path("/nonfiltered")
    @GET
    public Hello raw() {
        return new Hello("raw hello");
    }
}

:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Sample {

    String value() default "";
}

DynamicFeature Filter

@Provider
public class SampleFeature implements DynamicFeature {

    private SampleFilter sampleFilter;

    public void configure(ResourceInfo resourceInfo, FeatureContext context) {
        if (resourceInfo.getResourceMethod().getAnnotation(Sample.class) != null) {
            if (sampleFilter == null) {
                this.sampleFilter = new SampleFilter();
            }
            context.register(sampleFilter);
        }
    }
}

, , , ExtendedUriInfo, . :

public class SampleFilter implements ContainerRequestFilter {

    public SampleFilter() {
    }

    public void filter(ContainerRequestContext containerRequestContext) throws IOException {
        String sampleValue = this.getAnnotation(containerRequestContext).value();
        // do some filtering based on the Sample Value
        }

    private Sample getAnnotation(ContainerRequestContext requestContext) {
        ResourceMethod method = ((ExtendedUriInfo) (requestContext.getUriInfo()))
                .getMatchedResourceMethod();
        Method invokedMethod = method.getInvocable().getHandlingMethod();
        return invokedMethod.getAnnotation(Sample.class);
    }
}
+1

All Articles