I am using JAX-RS and it has default implementations for @OPTIONS
and @HEAD
methods, but I would like to provide a different functionality.
What I have done currently is this:
@GET
@Path("path/to/resource")
@Produces(MediaType.APPLICATION_JSON)
public Response resourceCall(){
// Normal method implementation
}
@OPTIONS
@Path("path/to/resource")
@Produces(MediaType.APPLICATION_JSON)
public Response resourceCall(){
Response.status(Response.Status.METHOD_NOT_ALLOWED).build();
}
So, basically I create a new call to each one of my resources. But, I would like to have a catch-all method here that would treat all my calls to @OPTION
or to @HEAD
.
How do I implement such functionality?
EDIT:
Just for clarity. I know how to do this using a Servlet Filter but, I am wondering if JAX-RS has a similar feature built-in for this specific case.
Since you are using Jersey, Jersey has a feature that allows you to programmatically add and modify resources. So you could add OPTIONS
and HEAD
methods to all your resources, without having to touch your resource classes. Below is an example that does nothing but send a 405 with a No <Method>
message. Probably not what you want, but you should be able to figure out what you need to modify to get what you want.
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.core.Configuration;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
import org.glassfish.jersey.process.Inflector;
import org.glassfish.jersey.server.model.ModelProcessor;
import org.glassfish.jersey.server.model.Resource;
import org.glassfish.jersey.server.model.ResourceModel;
@Provider
public class HeadAndOptionsModelProcessor implements ModelProcessor {
@Override
public ResourceModel processResourceModel(ResourceModel resourceModel,
Configuration configuration) {
ResourceModel.Builder resourceModelBuilder = new ResourceModel.Builder(false);
for (Resource rootResource: resourceModel.getResources()) {
final Resource.Builder rootResourceBuilder = Resource.builder(rootResource);
addOptions(rootResourceBuilder);
addHead(rootResourceBuilder);
for (Resource childResource: rootResource.getChildResources()) {
final Resource.Builder childResourceBuilder = Resource.builder(childResource);
addOptions(childResourceBuilder);
addHead(childResourceBuilder);
rootResourceBuilder.addChildResource(childResourceBuilder.build());
}
resourceModelBuilder.addResource(rootResourceBuilder.build());
}
return resourceModelBuilder.build();
}
@Override
public ResourceModel processSubResource(ResourceModel subResourceModel,
Configuration configuration) {
return subResourceModel;
}
private void addOptions(Resource.Builder resourceBuilder) {
resourceBuilder.addMethod("OPTIONS")
.handledBy(new Inflector<ContainerRequestContext, Response>() {
@Override
public Response apply(ContainerRequestContext context) {
return getOptionsResponse(context);
}
}).produces(MediaType.TEXT_PLAIN).extended(true);
}
private void addHead(Resource.Builder resourceBuilder) {
resourceBuilder.addMethod("HEAD")
.handledBy(new Inflector<ContainerRequestContext, Response>() {
@Override
public Response apply(ContainerRequestContext context) {
return getHeadResponse(context);
}
}).produces(MediaType.TEXT_PLAIN).extended(true);
}
private static Response getOptionsResponse(ContainerRequestContext context) {
return Response.status(Response.Status.METHOD_NOT_ALLOWED).entity("No Options").build();
}
private static Response getHeadResponse(ContainerRequestContext context) {
return Response.status(Response.Status.METHOD_NOT_ALLOWED).entity("No Head").build();
}
}