Post

spring-webmvc 4.3.x와 5.x.x의 차이 - HttpMessageNotWritableException

상황

spring-webmvc 4에서 5로 버전업하면서 특정 컨트롤러에서 아래 에러 발생

1
2
org.springframework.http.converter.HttpMessageNotWritableException: 
No converter for [class dev.umbum.MyExceptionResponse] with preset Content-Type 'application/vnd.ms-excel'
1
2
3
4
5
@GetMapping("/excel")
public MyResponse 문제의_컨트롤러(HttpServletResponse response, MyRequest request) {
    response.setContentType("application/vnd.ms-excel");  // <-- 이 부분
    ... // throw RuntimeException
}
1
2
3
4
5
6
7
// global exception handler
@ExceptionHandler({RuntimeException.class})
public ResponseEntity<MyExceptionResponse> handleDefaultRuntimeException(...) {
    return new ResponseEntity<>(
        new MyExceptionResponse(), HttpStatus.INTERNAL_SERVER_ERROR
    );
}

원인

spring-webmvc 5.0.x 부터는 outputMessage (HttpServletResponse)에 ContentType이 설정되어 있으면 이 값으로 고정해서 MessageConverter를 찾는다. (설정 안되어 있으면 로직으로 찾는다.)

spring-webmvc 5.0.x의 AbstractMessageConverterMethodProcessor.java#L206-L252

contentType을 HttpServletResponse에 설정된 그대로 application/vnd.ms-excel로 고정한다.

MyExcepionResponse 객체를 application/vnd.ms-excel 타입으로 변환 가능한 Converter가 있는지 찾는다. 당연히 안나온다. convert 불가하니 Exception 발생

반면 spring-webmvc 4.3.x 에서는 outputMessage (HttpServletResponse)에 ContentType이 설정되어 있든 아니든 무시하고 적절한 mediaType을 탐색한다.

spring-webmvc 4.3.x의 AbstractMessageConverterMethodProcessor.java#L175-L217

HttpServletResponse를 아예 안본다. acceptableMediaType, ProducibleMediaType, compatibleMediaType 등을 계산해서 mediaType을 설정하니 application/json이 된다.

해결

response에 ContentType 설정하는 부분을 return 직전으로 옮김.

This post is licensed under CC BY 4.0 by the author.