简体   繁体   中英

Spring Boot 1.4.3 and @ControllerAdvice

I have a spring 4 application with a ControllerAdvice extending ResponseEntityExceptionHandler that works fine when an exception rises.

@ControllerAdvice
@Slf4j
public class ExceptionManager extends ResponseEntityExceptionHandler {

    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
                                                                  HttpHeaders headers,
                                                                  HttpStatus status,
                                                                  WebRequest request) {
        final ValidationErrors errors = getErrors(ex.getBindingResult());
        headers.setContentType(MediaType.APPLICATION_JSON);
        return handleExceptionInternal(ex, errors, headers, HttpStatus.BAD_REQUEST, request);
    }


    @Override
    protected ResponseEntity<Object> handleBindException(BindException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        final ValidationErrors errors = getErrors(ex.getBindingResult());
        headers.setContentType(MediaType.APPLICATION_JSON);
        return handleExceptionInternal(ex, errors, headers, HttpStatus.BAD_REQUEST, request);
    }

    @ExceptionHandler(ValidationException.class)
    public ResponseEntity handleValidationException(ValidationException ex) {
        log.warn("Validation error", ex);
        return ex.toResponseEntity();
    }

    @ExceptionHandler(HttpClientErrorException.class)
    public ResponseEntity handleHttpClientErrorException(HttpClientErrorException ex) {
        log.error(ex.getMessage());
        return new ResponseEntity(ex.getResponseBodyAsString(), ex.getStatusCode());
    }

    @ExceptionHandler({Exception.class, RuntimeException.class})
    protected ResponseEntity<Object> handleRootException(Exception ex, WebRequest request) {
        return handleException(request, ex);
    }

...
}

However, in case of unmarshaller exception, for exemple

Exception received: 
org.springframework.http.converter.HttpMessageNotReadableException: Could not unmarshal to [class com.company.etc.v1.PojoResponse]: null; nested exception is javax.xml.bind.UnmarshalException
 - with linked exception:
[org.xml.sax.SAXParseException; lineNumber: 5; columnNumber: 28; Attribute name "entResponse" associated with an element type "assetDocum" must be followed by the ' = ' character.]
    at org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter.readFromSource(Jaxb2RootElementHttpMessageConverter.java:149)
    at org.springframework.http.converter.xml.AbstractXmlHttpMessageConverter.readInternal(AbstractXmlHttpMessageConverter.java:61)
    at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:193)
    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:104)
    at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:917)
    at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:901)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:655)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613)
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:531)
    at com.company.service.impl.SearchAsset.searchAssets(SearchAsset.java:42)
    ... 57 common frames omitted
Caused by: javax.xml.bind.UnmarshalException: null
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.createUnmarshalException(AbstractUnmarshallerImpl.java:335)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.createUnmarshalException(UnmarshallerImpl.java:563)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:249)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:214)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:140)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:123)
    at org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter.readFromSource(Jaxb2RootElementHttpMessageConverter.java:133)
    ... 127 common frames omitted
Caused by: org.xml.sax.SAXParseException: Attribute name "entResponse" associated with an element type "assetDocum" must be followed by the ' = ' character.
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:203)
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(ErrorHandlerWrapper.java:177)
    ... 131 common frames omitted

the exception is not catched! It happens in a specific case, when a @RestController uses a service that calls an external endpoint. In my case, the external service returns an XML, and if it is broken (like in the exception above), then the SAXParseException is not catched and automagically converted as a 400 Bad Request with an empty body by spring. It is also not logged at all.

If, in my RestController, I add a method @ExceptionHandler(Throwable.class) , this one is called and I can control the error sent back.

Is this normal? I was thinking that the ControllerAdvice could centralize all the exception handling, removing the need to have ExceptionHandler in each and every controller.

Just found the solution: remove the extends ResponseEntityExceptionHandler . Looks like it works better if you @ControllerAdvice doesn't extend anything.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM