ziggy
ziggy

Reputation: 15876

Catching exceptions from a Jersey REST client thrown from a Spring MVC Rest service

I implemented a REST application using Spring MVC, Jersey and JAXB.

The client sends a ServiceRequest object which contains information about the request and receives a ServiceResponse object back with information about the response.

ServiceRequest

@XmlRootElement(name = "servicerequest")
public class ServiceRequest{

    String serviceName = "AddUser"

    public String getServiceName() {
        return serviceName;
    }

    @XmlElement
    public void setServiceName(String serviceName) {
        this.serviceName = name;
    }   
}

ServiceResponse

@XmlRootElement(name = "serviceresponse")
public class ServiceResponse {

    String responseCode; 

    public String getResponseCode() {
        return responseCode;
    }

    @XmlElement
    public void setResponseCode(String code) {
        this.responseCode = name;
    }   
}

The client makes the call to the service using Jersey

ServiceClient

ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
WebResource service = client.resource(RESOURCE_URL);

ServiceRequest request = new ServiceRequest();
ServiceResponse response = service.path("addUser").type(MediaType.APPLICATION_XML)
.accept(MediaType.APPLICATION_XML).entity(request).post(ServiceRequest.class);

On the server side, the service gets the request, handles it and returns a ServiceResponse object.

@RequestMapping(method = RequestMethod.POST, 
            value = "/addUser",headers="Accept=application/xml")
    @ResponseStatus(HttpStatus.OK)  
public @ResponseBody ServiceResponse addUser(@RequestBody ServiceRequest request) {

        ServiceResponse response = new ServiceResponse();

        //Handle request
        //service.addUser();

        response.setCode("200");
        return response; 
}

The controller class shown above makes a call to another service class to handle the request (service.addUser()). This service class can raise a number of exceptions.

What i am not sure of is how best to handle them. After googling around, i found that i can use an ExceptionHandler as shown below:

@ExceptionHandler(NullPointerException.class)
@ResponseBody
public String handleException1(NullPointerException ex)
{
    return ex.getMessage();
}

I can have the controllers extend a base class that has the exception handler.

A couple of questions regarding the above approach:

And finally, i noticed that the ExceptionHanlder can only have a return type that is one of the following:

ModelAndView
Model
Map
View
String – interpreted as a view name
void, but only if the method writes directly to the response object

I thought i can create the ServiceResponse object in the ExceptionHandler and set the appropriate code and return the ServiceResponse object. This however is not possible if i cant return a ServiceResponse type in the excpetion handler.

Edit

I tried using the ExceptionHandler using a generic exception class as shown below

@ExceptionHandler(ServiceException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
    public @ResponseBody resolveServiceValidationException(ServiceException ex) {       

        System.out.println("In resolveServiceError");

        ServiceResponse = new ServiceResponse();
        response.setResponseException(ex.getMessage());
        return response;        
    } 

The exception is being caught but the ServiceResponse object is always null. All i get is the following message:

GET http://localhost:8080/myService/services/pingError returned a response status of 400 Bad Request

How can i access the response object when an exception is returned back?

Thanks

Upvotes: 3

Views: 6908

Answers (1)

soulcheck
soulcheck

Reputation: 36777

  1. @ExceptionHandler annotation can take an array of classes as a parameter, so you can create only one (or more) handlers for multiple exceptions. Change the method signature to take the common ancestor of all handled exception classes as a parameter. Something along the lines:

    @ExceptionHandler(value = {NullPointerException.class, AnotherException.class})
    @ResponseBody
    public String handleException1(Exception ex) {
        return ex.getMessage();
    }
    
  2. In your case it'll be String, since you annotated it with @ResponseBody, but you probably want to change the returned http code to some error code. You can do it by adding

    @ResponseStatus(value = HttpStatus.WHATEVER_CODE_YOU_WANT, reason = "Your message")` 
    

    annotation to your exception handler.

  3. In case when http code returned by the call is greater or equal than 300, jersey client throws UniformInterfaceException. You can catch and handle it. The response type doesn't matter in this case, as the exception is thrown before the conversion.

update

Once you get a hold of UniformInterfaceException and change the exception handler on the server so it returns ServiceResponse as response body, then you can get the reponse using:

ServiceResponse response = uniformInterfaceException.getResponse().getEntity(ServiceResponse.class);

Upvotes: 4

Related Questions