본문 바로가기

Logging/Spring

[Spring MVC] org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 오류

728x90

API 테스트를 하다가 이해가 안되는 상황이 발생했는데, 이런 상황이 발생할 수도 있구나 싶고 누군가에게 도움이 될 수도 있을 것 같아서 짧게 기록해둔다. 

 

 

다음과 같은 페이징 조회를 하여 특정 테이블에서 추천 인스턴스들을 반환하는 요청을 만든 후 API 테스트를 하던 중 발생하였다. 

 

 

@GetMapping("/api/v0/hello/suggest")
    public ResponseEntity<?> getHello(
            @RequestParam(required = false, defaultValue = "") String aFilter
            , @RequestParam(required = false, defaultValue = "") String bFilter
            , @RequestParam(defaultValue = "-1") int offset
            , @RequestParam(required = false, defaultValue = "20") int limit
            , @AuthenticationPrincipal @ApiIgnore SecurityMember principal) {

        if (offset == -1) {
            throw new Exception(EXCEPTION_REASON); // 필수 parameter 누락,
        }
        ...
}

 

 

API 테스트를 시도하고 요청을 날려보니, 다음과 같은 에러가 발생하였다.

 

 

2024-01-29 12:39:40.879 WARN 8014 --- [nio-8080-exec-6] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.lang.Long'; nested exception is java.lang.NumberFormatException: For input string: "suggest"]

 

 

 

대충 썸네일을 위한 오류 이미지

 

 

 

로그를 보면 해당 요청이 수신해야 하는 Parameter 중 타입이 잘못 매핑된 것이 있다는 줄 알아서 이상하다고 생각했다. 왜냐하면 첫 요청은 offset 에 관련해서 예외가 나는지 확인하기 위해서 아무 Parameter 없이 /api/v0/hello/suggest 로만 요청을 시도했기 때문이다. 

 

 

결론부터 말하자면 그게 아니고, 요청 Matcher 가 중복되기 때문에 발생한 현상이였다. 내가 만든 Hello 란 도메인에 많은 요청 목록을 보면 다음과 같았다. 

 

 

* POST - /api/v0/hello (CREATE)
...
* GET - /api/v0/hello/{helloId} (세부조회)
...
* DELETE - /api/v0/hello/{helloId} (삭제)
* GET - /api/v0/hello/suggest (추천 Hello 조회, 방금 만든 것) 

 

 

이와 같은 상황에서, suggest 의 경로로 요청을 날리니, DispatcherServlet 에서 핸들러 매핑을 할 때, 두번째 세부 조회 요청으로 인지하고, helloId 는 Long 타입인데 "suggest" 라는 String 으로 날렸다고 해당 예외를 발생시킨 것이였다. 삭제 요청은 HTTP 메소드가 다르기 때문에 무시할 수 있다. 

 

 

같은 Method 에서는 기본적인 CRUD 요청외 다른 API 들을 제공할 때, 기본 경로와 중복되는 경로가 없는지 확인하는 것이 중요할 것 같다. Sugget 하는 요청 경로를 수정하니, 정상적으로 동작하는 모습을 확인할 수 있었다. (/api/v0/hello/main/suggest 정도로)

 

 

다만, 궁금한 점은 API Tester 로 테스트하는 것은 MockMvc 로 Controller 수신 테스트를 모두 완료한 뒤였다. 그러면 왜 Controller Test 할 때는 해당 예외가 발생하지 않았는지 궁금하다. 아마 MockMvc 로 테스트하는 환경인 @AutoConfigureMockMvc, @SpringBootTest(webEnvironment=SpringBootTest.WebEnvironment.MOCK) 로 환경을 구성하면 조금 다르게 동작하기 때문일 수도 있겠다고 생각이 들었다. 하지만 같은 똑같이 핸들러 매핑을 하는 과정을 겪을 것 같긴 한데, 왜 MockMvc 로 테스트할 때는 발생하지 않았는지 의문이긴 하다 

 

 

디버거를 걸고 하나씩 파헤쳐보면 알 수도 있을 수도.. 있지만 나중에 하기로 하고 잠깐 미루도록 하겠다. Mock 환경에 대해서 정확하게 이해를 하지 못했기 때문에 의문인 부분이다.

 

728x90