26

I am trying to do some validation on requests coming into my service using the ContainerRequestFilter. Everything is working fine, however there is one problem - every single request gets pass through the filters, even though some of the filters will never apply to them (one filter only validates on ResourceOne, another only on ResourceTwo etc.)

Is there a way to set a filter only to be invoked on a request under certain conditions?

While it is not a blocker or hindrance, it would be nice to be able to stop this kind of behaviour :)

dur
  • 15,689
  • 25
  • 79
  • 125
KingTravisG
  • 1,316
  • 4
  • 21
  • 43

3 Answers3

53

I assume that You are using Jersey 2.x (implementation for JAX-RS 2.0 API).

You have two ways to achieve Your goal.

1. Use Name bindings:


1.1 Create custom annotation annotated with @NameBinding:

@NameBinding
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationForResourceOne {}

1.2. Create filter with Your annotation:

@Provider
@AnnotationForResourceOne
public class ResourceOneFilter implements ContainerRequestFilter {
...
}

1.3. And bind created filter with selected resource method:

@Path("/resources")
public class Resources {
    @GET
    @Path("/resourceOne")
    @AnnotationForResourceOne
    public String getResourceOne() {...}
}

2. Use DynamicFeature:


2.1. Create filter:

public class ResourceOneFilter implements ContainerRequestFilter {
...
}

2.2. Implement javax.ws.rs.container.DynamicFeature interface:

@Provider
public class MaxAgeFeature implements DynamicFeature {
    public void configure(ResourceInfo ri, FeatureContext ctx) {
        if(resourceShouldBeFiltered(ri)){
            ResourceOneFilter filter = new ResourceOneFilter();
            ctx.register(filter);
        }
    }
}

In this scenario:

  • filter is not annotated with @Provider annotation;
  • configure(...) method is invoked for every resource method;
  • ctx.register(filter) binds filter with resource method;
marpme
  • 2,363
  • 1
  • 15
  • 24
pWoz
  • 1,649
  • 3
  • 20
  • 30
  • 6
    Are you sure `@PreMatching` annotation is needed in NameBinding example? – Zakhar Sep 07 '15 at 07:28
  • 2
    @Zakhar You are right if we use `@PreMatching` the filter/interceptor will apply to all the requests regardless of the annotations which makes `@NameBinding` useless. For more info please see https://jersey.java.net/documentation/latest/filters-and-interceptors.html – sajjadG Oct 03 '16 at 12:03
  • I used named filter but it is applying to all the requests regardless which I annotated which I didn't. I don't have @PreMatching for the filter. Please help – Kuldeep Yadav Feb 03 '20 at 04:37
11

When we use @NameBinding we need to remove @PreMatching annotation from the Filter. @PreMatching causes all the requests go through the filter.

dur
  • 15,689
  • 25
  • 79
  • 125
Arun Avanathan
  • 982
  • 4
  • 11
  • 26
2

@PreMatching does not work together with @NameBinding, because the resource class/method is not yet known in pre-matching phase. I solved this issue by removing @PreMatching from the filter and using binding priority. See ResourceConfig.register(Object component, int bindingPriority).

Filters to be executed before the resource simply get a higher priority.

croxy
  • 4,082
  • 9
  • 28
  • 46