Custom Jersey Error Handling, how to catch respons

2019-05-14 00:56发布

问题:

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?

回答1:

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;
}


回答2:

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.