5

I have a controller advice class, but I can't seem to get it to return XML, even though I've used the @RequestMapping annotation. Here's a stripped-down example.

@RestControllerAdvice
public class ControllerAdvice {    
    @ExceptionHandler(Exception.class)
    @RequestMapping(produces = MediaType.APPLICATION_XML_VALUE)
    public PriceAvailabilityResponse handleControllerErrorXML(final Exception e) {
        e.printStackTrace();
        System.out.println("Exception Handler functional");
    
        PriceAvailabilityResponse priceAvailabilityResponse = new PriceAvailabilityResponse();
        priceAvailabilityResponse.setStatusMessage("Server Error");
        priceAvailabilityResponse.setStatusCode(99);
        
        return priceAvailabilityResponse;
    }
}

Note how @RequestMapping(produces = MediaType.APPLICATION_XML_VALUE) works in rest controllers to control how the response is formed.

And here's an example of what the PriceAvailabilityResponse could be from the aforementioned block of code.

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@Getter
@Setter
public class PriceAvailabilityResponse {
    @JacksonXmlProperty(isAttribute = true, localName = "StatusCode")
    @JsonProperty(value = "StatusCode", required = false)
    private int statusCode = 0;

    @JacksonXmlProperty(isAttribute = true, localName = "StatusMessage")
    @JsonProperty(value = "StatusMessage", required = false)
    private String statusMessage;
}

And below is an example rest controller method to throw the error

@RequestMapping(value = "/error_test", produces = MediaType.APPLICATION_XML_VALUE)
public PriceAvailabilityResponse getPriceResponse() throws Exception{
    int x = 1/0;
    return null;
}

I've written the model for this code to return both JSON and XML depending on which endpoint is hitting the microservice, that is absolutely imperative.

Unfortunately, when I hit the /error_test path, my response always comes in JSON.

enter image description here

How could I force the response to be XML? Thanks so much for your time.

geekTechnique
  • 850
  • 1
  • 11
  • 38
  • in your postman chnage json to xml – A.khalifa Sep 10 '19 at 18:29
  • 1
    My postman is not changing the response. I am able to get XML responses if I don't have the code error out. If I change that dropdown box to "xml", it just reformats the json, and not in an format. Thank you for your interest in my problem. – geekTechnique Sep 10 '19 at 18:48

1 Answers1

11

Below approach should solve your problem

@RestController
public class TestController {

    @GetMapping(value = "/throw-exception", produces = MediaType.APPLICATION_XML_VALUE)
    public ResponseEntity throwException(){
        throw new CustomException("My Exception");
    }
}

Return response entity from exception handler and specify the media type with it.

@ControllerAdvice
public class GlobalErrorHandler extends ResponseEntityExceptionHandler {

@ExceptionHandler(value = {CustomException.class})
protected ResponseEntity handleInvalidDataException(
        RuntimeException ex, WebRequest request) {

    PriceAvailabilityResponse priceAvailabilityResponse = new 
    PriceAvailabilityResponse();
    priceAvailabilityResponse.setStatusMessage("Server Error");
    priceAvailabilityResponse.setStatusCode(99);

    return ResponseEntity.status(HttpStatus.BAD_REQUEST)
            .contentType(MediaType.APPLICATION_XML)
            .body(priceAvailabilityResponse);
}

Include jackson-dataformat-xml dependency if you don't have one

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.9.8</version>
</dependency>
geekTechnique
  • 850
  • 1
  • 11
  • 38
Suraj
  • 737
  • 6
  • 21
  • I really appreciate your answer. I won't be able to test it until tomorrow, but rest assured, I will be testing it tomorrow. Thank you so much, I'll let you know if it works. – geekTechnique Sep 10 '19 at 20:46
  • Hey, I was attempting to implement your answer, I can't figure out what to put in place of `ExceptionDto` in your second code block. I'm sure this is obvious to most, but I'm pretty new to spring boot. Thanks again. – geekTechnique Sep 11 '19 at 13:55
  • 1
    @geekTechnique I have update the answer. Basically ExceptionDto was the response body which I wanted to throw from error handler. You can return priceAvailabilityResponse as response body in the error. – Suraj Sep 11 '19 at 15:21
  • 1
    This has been such a big problem for me. Thank you so much; I'm very grateful! This worked, but I had to remove `.build())` from your middle code block to get it to compile. – geekTechnique Sep 11 '19 at 18:34