3
votes

I'm trying out some custom error handling on my webservice. In my webservice, I created a custom Exception class extending WebApplicationException as described in JAX-RS / Jersey how to customize error handling? :

public class InternalServerErrorException extends WebApplicationException {
    public InternalServerErrorException(String message) {
        super(Response.status(Response.Status.INTERNAL_SERVER_ERROR)
            .header("errorMessage", message).type(MediaType.TEXT_PLAIN).build());
        System.out.println(message);
    }
}

For testing, I have a simple Country service that gives a list of countries. I made sure that an error will occur to test the throwing of the InternalServerErrorException:

@GET
@Override
@Path("countries")
@Produces({"application/xml"})
public List<Country> findAll() {
    try {
        int i = Integer.parseInt("moo"); //<-- generate error
        List<Country> countries = super.findAll();
        return countries;
    } catch (Exception ex) {
        throw new InternalServerErrorException("I want this message to show at client side");
    }
}

At my client I have a CountryClient with following method:

public List<Country> findAll() throws ClientErrorException {
    WebTarget resource = webTarget;
    resource = resource.path("countries");
    return resource.request(javax.ws.rs.core.MediaType.APPLICATION_XML).get(new GenericType<List<Country>>(){});
}

And in my controller I use it like this:

    try {
        CountryClientSSL cc = new CountryClientSSL();
        cc.setUsernamePassword(USERNAME, PASSWORD);
        ObservableList<Country> olCountries = FXCollections.observableArrayList(cc.findAll());

        tblCountries.setItems(olCountries);
        tcCountry.setSortType(SortType.ASCENDING);
        tblCountries.getSortOrder().add(tcCountry);
    } catch (Exception ex) {
        System.out.println(ex.getMessage());
    }

So everytime I use the findAll() method in my client, I see following info in my output windows: Info: I want this message to show at client side at server side, and HTTP 500 Internal Server Error at client side.

Is there a way to get the errorMessage on the client side (in the catch block) without using Response as a return type?

What I'm trying to achieve is the following: When an error occurs on the client side, the users can send a debug report to my JIRA instance which contains alot of info like the stacktrace of the client, extra information about the system, who's logged in, ... It would be nice to attach the stacktrace of the server in there as well. Or are there better ways to achieve that?

2
Is there a reason why you can't submit the exception to JIRA from the server side? That would be by far the easiest way to upload all the exception detail. Otherwise you'll have to serialise it to JSON or some other format so the client can do it.jas_raj
Basicly because I want the client side error information and server side error information to be linked. What I can do is create a JIRA issue from server side, then put the unique key as errorMessage and link it to the issue being created at client side... but then I still need to get the errorMessage string at client side. That results in 2 issues for one actual issue thou...Perneel
For Jersey 2 if somebody wants to suppress the exception on a 500 response code see this answer: stackoverflow.com/a/31360598/403999Juan Rojas

2 Answers

5
votes

Is there a way to get the errorMessage on the client side (in the catch block) without using Response as a return type?

You can use response.readEntity(new GenericType<List<Country>>(){}). This way you will still have access to the Response. Though in this case there will be no stacktrace. There is only an exception on the client when you try to use get(ParsedType). The reason is that with get(ParsedType), there is no other way to handle the error status. But using Response, the developer should do the checking against the status. So the method could look more like

public List<Country> findAll() throws ClientErrorException {
    WebTarget resource = webTarget;
    resource = resource.path("countries");
    Response response =  resource.request(javax.ws.rs.core.MediaType.APPLICATION_XML).get();
    if (response.getStatus() != 200) {
        System.out.println(response.getHeaderString("errorResponse"));
        return null;
    } else {
        return response.readEntity(new GenericType<List<Country>>(){});
    }
}

Though instead of in the header, I would just send the message out as the response body. That's just me

super(Response.status(Response.Status.INTERNAL_SERVER_ERROR)
        .entity( message).type(MediaType.TEXT_PLAIN).build());

Client side

if (response.getStatus() != 200) {
    System.out.println(response.readEntity(String.class));
    return null;
}
0
votes

I don't believe that you can return custom content (i.e. errorMessage) in any response type except HTTP 200 (Response.ok().build).

However, you can throw exceptions within your server code and then catch them and convert them to valid responses with an ExceptionMapper. See this question for more details.