Reputation: 15876
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:
ServiceResponse
, what would be the object type that would be returned when an exception occurs? ServiceResponse
type. How does it work if the response is an exception type?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.
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
Reputation: 36777
@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();
}
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.
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