I am developing a web service using the JAX-RS API with Jersey 1.17 as my implementation.
I want clients to have the choice between JSON and XML which they specify using the Accept
HTTP header. I want JSON to be the default when a client does not include the Accept
header in the request. I have tried to achieve this by placing MediaType.APPLICATION_JSON
before MediaType.APPLICATION_XML
in the Produces
annotation.
This seems to work in normal situations:
$ curl 'http://localhost:8080/webservice/Bob'
{"text":"Hello, Bob"}
$ curl -H'Accept: application/json' 'http://localhost:8080/webservice/Bob'
{"text":"Hello, Bob"}
$ curl -H'Accept: application/xml' 'http://localhost:8080/webservice/Bob'
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Greeting text="Hello, Bob"/>
But if I throw a WebApplicationException
from the constructor of my resource class, the response media type defaults to XML:
$ curl 'http://localhost:8080/webservice/Vader'
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Error message="Illegal name"/>
If the client includes the Accept
header the media type is correct:
$ curl -H'Accept: application/json' 'http://localhost:8080/webservice/Vader'
{"message":"Illegal name"}
How can I configure Jersey to use the default even for errors that are thrown from the resource class constructor?
Here is the code of my resource class (full example on GitHub):
package org.example.errorhandling;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.example.errorhandling.repr.Error;
import org.example.errorhandling.repr.Greeting;
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Path("/{name}")
public class Greeter {
private final String name;
public Greeter(@PathParam("name") String name) {
if ("Vader".equals(name)) {
Error error = new Error();
error.message = "Illegal name";
Response errorResponse = Response.status(Status.BAD_REQUEST).entity(error).build();
throw new WebApplicationException(errorResponse);
} else {
this.name = name;
}
}
@GET
public Response greet() {
Greeting greeting = new Greeting();
greeting.text = "Hello, " + name;
return Response.ok(greeting).build();
}
}
This problem has a workaround due to a suggestion from usul_.
The workaround is to use the
selectVariant()
mechanism to programmatically choose a media type that matches theAccept
header in the request. This makes it possible to enforce the default media type at the cost of repeating the preferred order.Here is the constructor modified to use this technique (full code on GitHub):
Have you tried to use Jersey Exception Mappers ? Here is an example https://github.com/jersey/jersey/blob/master/examples/exception-mapping/src/main/java/org/glassfish/jersey/examples/exception/Exceptions.java