3

i have one REST API method :which will return Xml as response . Just for simplicity assume it throws simple Exception.

@RequestMapping(value = "machine/xmlData", method = RequestMethod.GET, produces = "application/xml")
    public ResponseEntity<String> getXml(HttpServletRequest request)
            throws Exception {
        return getDataFromService();

}

Now i am handling the Exception in REST Controller like this. This is generic Exception Handle method, for other API methods as well.(Xml or JSON Response)

 @ExceptionHandler(Exception.class)
        @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
        public ResponseEntity HandleException(Exception ex, HttpServletRequest request) {
            ex.printStackTrace();
           // here logic to generate Custom error Object
            return new ResponseEntity<Object>(customErrorObject, HttpStatus.INTERNAL_SERVER_ERROR);
        }

Case 1: Accept :"application/xml" and valid Response from Service Everything works fine.

Case 2: Accept :"application/xml" and Exception from Service then i get 406 Not Representable

As per my understanding it is

because ResponseEntity from HandleException is JSON and accept header is "application/xml" thats why i am getting 406.

Is there anyway that i can send the error Response from HandleException method as xml and json ? I know on REST API methods we can define something like this produces={"application/json","application/xml"} i am struggling to put this on HandleException Method.

Any tip would be of great help.

Thanks.

lesnar
  • 2,400
  • 7
  • 41
  • 72

1 Answers1

2

You could take advantage of the spring-mvc HttpMessageConverters by using the @ResponseBody annotation( https://spring.io/blog/2013/05/11/content-negotiation-using-spring-mvc). This annotation is responsible for choosing the correct messageConverter for a given response type.

For your response to be xml or json compatible you need to do the following:

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class WrappedExceptionResponse {
    public String respone;

    public String getRespone() {
        return respone;
    }

    public void setRespone(String respone) {
        this.respone = respone;
    }
}

And change your exception handler method to

    @ExceptionHandler(Exception.class)
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    public @ResponseBody WrappedExceptionResponse HandleException(Exception ex, HttpServletRequest request) {
//        ex.printStackTrace();
       // here logic to generate Custom error Object
        WrappedExceptionResponse resp=new WrappedExceptionResponse();
        resp.setRespone(ex.getMessage());
    return resp;

And then your exception response would be dependent on the content-type you give.

Alex Ciocan
  • 2,272
  • 14
  • 20
  • but then its static , i cant use it for JSON MediaTypes. I would like to have some Generic Error Response. – lesnar Dec 05 '16 at 10:25
  • 1
    Eddited my answer please check if it works as expected for both json and xml . – Alex Ciocan Dec 05 '16 at 11:26
  • it does not help. @ResponseBody is not automatically using the right convertor. – lesnar Dec 05 '16 at 14:15
  • If you change your rest endpoint to @RequestMapping(value = "machine/xmlData", method = RequestMethod.GET, produces = {"application/xml","application/json"}). Then the response type would be different with headers like Accept:application/json or Accept:application/xml. The response type is closely related to your Accept header for get requests. – Alex Ciocan Dec 05 '16 at 21:02
  • Adding jackson xml dependency helped. – lesnar Dec 06 '16 at 07:33
  • How to do the same for Spring >= 5.1? According to the documentation: "Content Negotiation for Error Responses The produces condition of an @RequestMapping no longer impacts the content type of error responses". – Bakus123 Feb 26 '20 at 08:09
  • If you use ResponseEntity as a wrapper for your returning type, i think it should work – Alex Ciocan Feb 26 '20 at 09:21