users@jersey.java.net

Re: [Jersey] Returning response in JSON format in case of Exceptions

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Mon, 03 May 2010 13:05:16 +0200

Hi Jonathan,

On May 1, 2010, at 5:37 PM, Jonathan Hodges wrote:

> Is this the correct approach to deal with this exception use case?
> I realize that I might not be following best practices with the
> method declaring a return MIME type of ‘text/plain’ but in exception
> cases return ‘application/json’ or ‘application/xml.’ Is this
> causing the issue by chance?
>

Yes. Because of @Produces({MediaType.TEXT_PLAIN}) Jersey will be
setting the content-type to text/plain even if exceptions thrown from
the resource method are mapped to responses that do not set the
content-type.

I suspect you were previously using a version of Jersey that did not
implement the above, and thus this has caused a subtle change in
behavior.

So in this case you need to explicitly check in your exception mapper
if XML or JSON is more acceptable and explicitly set the content type
accordingly, with a default if neither is acceptable.

You can also set the content type to null in the builder and i think
that will revert to the previous behavior you expected.


> Is this the correct approach to deal with this exception use case?
> I realize that I might not be following best practices with the
> method declaring a return MIME type of ‘text/plain’ but in exception
> cases return ‘application/json’ or ‘application/xml.’ Is this
> causing the issue by chance?


The server is free to override what the client considers most
acceptable. I think this is fine for status codes >= 400.

Paul.

On May 1, 2010, at 5:37 PM, Jonathan Hodges wrote:

> Hello,
>
> I am not sure if my issue is exactly the same as yours but it sounds
> similar so I figured I would pose my question in this thread instead
> of creating a new one. I also would like to return JSON or XML in
> the event of an exception. Consider the following scenario.
>
> Here is my server side resource method. Notice the MediaTypes that
> it consumes as well as produces.
>
>
> @PUT
> @Path("/saveUserActivity")
> @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
> @Produces({MediaType.TEXT_PLAIN})
> public String saveUserActivity(UserActivityListJAXB
> userActivityListJAXB)
> throws ValidationException, Exception {
>
> ...
> ...
> }
>
>
> Here is my ExceptionMapper.
>
>
> @Provider
> public class UserActivityRestValidationExceptionMapper implements
> ExceptionMapper<ValidationException> {
>
> private final Logger logger =
> LoggerFactory.getLogger(this.getClass());
>
> @Context
> HttpHeaders hh;
>
> public Response toResponse(ValidationException e) {
> logger.debug("ValidationException mapper: "+e.getClass().getName());
>
> ErrorList errorList = new ErrorList();
> Set<Error>errorSet = new HashSet<Error>();
> Error error = new Error();
> error.setCode(e.getValidationCode());
> error.setMessage(e.getMessage());
> errorSet.add(error);
>
> if (e.getValidationExceptions() != null &&
> e.getValidationExceptions().size() > 0) {
>
> for (ValidationException ve : e.getValidationExceptions()) {
> error = new Error();
> error.setCode(ve.getValidationCode());
> error.setMessage(ve.getMessage());
> errorSet.add(error);
> }
> }
> errorList.setError(errorSet);
>
> ResponseBuilder r = Response.status(Response.Status.BAD_REQUEST);
> r.type(hh.getAcceptableMediaTypes().get(0));
> //r.type(MediaType.APPLICATION_XML);
>
> r.entity(errorList);
>
> return r.build();
> }
> }
>
>
> Here is my test class
>
>
> @Test
> public void saveUserSocialIdentityTest() {
> UserSocialIdentityListJAXB userSocialIdentityListJAXB = new
> UserSocialIdentityListJAXB();
>
> ...
> ...
>
> String response =
> wr.path("saveUserSocialIdentity")
> .type(MediaType.APPLICATION_JSON_TYPE)
> .accept(MediaType.TEXT_PLAIN)
> .header("Version", "1.0")
> .put(String.class, userSocialIdentityListJAXB);
>
> assertTrue("Method: saveUserSocialIdentityTest \nMessage:
> Something wrong, the returned " +
> "response is not 'OK'", response.equals("OK"));
> }
>
>
> In the event a ValidationException is thrown the
> UserActivityRestValidationExceptionMapper.toResponse method is
> correctly invoked. However when attempting to return the JSON or
> XML I get the following error.
>
> May 1, 2010 9:01:10 AM
> com.sun.jersey.spi.container.ContainerResponse write
> SEVERE: A message body writer for Java class
> com.ge.nbc.common.error.jaxb.ErrorL
> ist, and Java type class com.ge.nbc.common.error.jaxb.ErrorList, and
> MIME media
> type text/plain was not found
>
> In the mapper I attempt to set the Response to the correct MIME type
> with the following code to no avail.
>
> ResponseBuilder r = Response.status(Response.Status.BAD_REQUEST);
> r.type(hh.getAcceptableMediaTypes().get(0));
> r.entity(errorList);
> return r.build();
>
> The frustrating this is this was working earlier this week. I have
> been pulling my hair out to figure out what I might have changed to
> make it fail. I am using the version 1.2-SNAPSHOT because it has a
> fix for including entities in PUT and DELETE methods. Is it
> possible something might have changed recently that would affect this?
>
> Is this the correct approach to deal with this exception use case?
> I realize that I might not be following best practices with the
> method declaring a return MIME type of ‘text/plain’ but in exception
> cases return ‘application/json’ or ‘application/xml.’ Is this
> causing the issue by chance?
>
> Thanks in advance for your help.
>
> -Jonathan
>
>
>
> On Fri, Apr 30, 2010 at 8:12 AM, j2eeuser32 <nagmidde_at_gmail.com>
> wrote:
>
> Hi
>
> I am trying to figure out how to return response in JSON format in
> the case
> of exceptions. I have mapped the exception using ExceptionMapper,
> but the
> overridden toResponse method only returns Response object.
>
> Here is my code. Any help/ideas would be greatly appreciated.
>
> Thanks
>
> <code>
> @Path("/test")
> public class TestResource {
> @GET
> @Path("/userinfo")
> @Produces(MediaType.APPLICATION_JSON)
> public String getUserInfo(@QueryParam("userId") String userId) {
> .....
> throw new TestException("User not available");
> }
> }
>
> @Provider
> public class TestExceptionMapper implements
> ExceptionMapper<TestException> {
> public Response toResponse(TestException ex) {
> return
> Response.status(404).entity(ex.getMessage()).type("application/
> json").build();
> }
> }
> </code>
> --
> View this message in context: http://jersey.576304.n2.nabble.com/Returning-response-in-JSON-format-in-case-of-Exceptions-tp4985840p4985840.html
> Sent from the Jersey mailing list archive at Nabble.com.
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>
>