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 직전으로 옮김.