I've used jersey to create webservices. I've created request filter using ContainerRequestFilter
. I've gone through Jersey Request Filter only on certain URI question but I want to exclude filter for some urls only.
@Provider
public class AuthFilter implements ContainerRequestFilter{
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// business logic
}
}
By default, filters doesn't support excluding a specific URL pattern, whenever you define a URL pattern for a filter then any request matching this pattern is handled by the filter without exceptions. The simplest way for excluding URLs from a filter is to map your filter to a very specific pattern.
Interface ContainerResponseFilterAn extension interface implemented by container response filters. By default, i.e. if no name binding is applied to the filter implementation class, the filter instance is applied globally to any outgoing response.
Interceptors share a common API for the server and the client side. Whereas filters are primarily intended to manipulate request and response parameters like HTTP headers, URIs and/or HTTP methods, interceptors are intended to manipulate entities, via manipulating entity input/output streams.
Instead of excluding URIs from a global filter, you could consider using a name binding filter to select the endpoints your filter will be bound to.
Also check this answer for some examples with name binding filters.
If you are still happy with the global filter approach, you could consider using the UriInfo
interface to get details about the requested URI. Use one of the following approaches to get an instance of UriInfo
:
Using the @Context
annotation:
@Provider
public class AuthFilter implements ContainerRequestFilter {
@Context
private UriInfo info;
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
...
}
}
Getting it from the ContainerRequestContext
:
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
UriInfo info = requestContext.getUriInfo();
...
}
Once you have the UriInfo
instance, you'll have access to a bunch of methods that may be useful:
getAbsolutePath()
: Get the absolute path of the request.getBaseUri()
: Get the base URI of the application.getMatchedResources()
: Get a read-only list of the currently matched resource class instances.getMatchedURIs()
: Get a read-only list of URIs for matched resources.getPath()
: Get the path of the current request relative to the base URI as a string.getPathSegments()
: Get the path of the current request relative to the base URI as a list of PathSegment
.getRequestUri()
: Get the absolute request URI including any query parameters.relativize(URI)
: Relativize a URI with respect to the current request URI.resolve(URI)
: Resolve a relative URI with respect to the base URI of the application.For more details, check the UriInfo
documentation.
If the requested URI does not match the URIs you want to apply the filter to, simply use a return
instruction:
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
UriInfo info = requestContext.getUriInfo();
if (!info.getPath().contains("secured")) {
return;
}
}
Another approach is dynamic binding. It allows you to assign filters and interceptors to the resource methods in a dynamic manner. Name binding, mentioned above, uses a static approach and changes to binding require source code change and recompilation. With dynamic binding you can implement code which defines bindings during the application initialization time.
The following example extracted from the Jersey documentation shows how to implement dynamic binding:
@Path("helloworld")
public class HelloWorldResource {
@GET
@Produces("text/plain")
public String getHello() {
return "Hello World!";
}
@GET
@Path("too-much-data")
public String getVeryLongString() {
String str = ... // very long string
return str;
}
}
// This dynamic binding provider registers GZIPWriterInterceptor
// only for HelloWorldResource and methods that contain
// "VeryLongString" in their name. It will be executed during
// application initialization phase.
public class CompressionDynamicBinding implements DynamicFeature {
@Override
public void configure(ResourceInfo resourceInfo, FeatureContext context) {
if (HelloWorldResource.class.equals(resourceInfo.getResourceClass())
&& resourceInfo.getResourceMethod().getName().contains("VeryLongString")) {
context.register(GZIPWriterInterceptor.class);
}
}
}
The binding is done using the provider which implements the DynamicFeature
interface. The interface defines one configure
method with two arguments, ResourceInfo
and FeatureContext
.
ResourceInfo
contains information about the resource and method to which the binding can be done. The configure method will be executed once for each resource method that is defined in the application. In the example above the provider will be executed twice, once for the getHello()
method and once for getVeryLongString()
(once the resourceInfo
will contain information about getHello()
method and once it will point to getVeryLongString()
).
If a dynamic binding provider wants to register any provider for the actual resource method it will do that using provided FeatureContext
which extends JAX-RS Configurable API. All methods for registration of filter or interceptor classes or instances can be used. Such dynamically registered filters or interceptors will be bound only to the actual resource method. In the example above the GZIPWriterInterceptor
will be bound only to the method getVeryLongString()
which will cause that data will be compressed only for this method and not for the method getHello()
.
Note that filters and interceptors registered using dynamic binding are only additional filters run for the resource method. If there are any name bound providers or global providers they will still be executed.
For more details, check the Jersey documentation about filters and interceptors.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With