
본 포스팅은 Spring Boot 3.3.4 를 다루고 있습니다.
문제 상황
스프링 부트에서 @PathVariable 어노테이션을 사용하는 메서드에서 오류가 발생했다.
(처음부터 @PathVariable이 문제의 원인이었다는 건 몰랐다.)
책으로 실습해 보며 공부할 때와 최대한 비슷하게 작성한 코드인데 오류가 났다.
우선, 문제가 발생한 메서드의 코드는 다음과 같다.

그런데, 클라이언트가 "/{id}" 주소로 GET 요청을 보내서 show.html 에 접속하면 오류 페이지가 나타난다.
왜일까 ?
시도
[ 1 ]
처음에는 show.html 의 페이지 구성 문법이 잘못되어 있나 싶었다.
그래서 사족을 떼고 최소한의 HTML 코드로 구성했다.
이때, Model 에 등록한 게시글의 정보를 가져오는 로직은 남겨놓았다.
HTML 에서의 오류는 최대한 잡아내고, Model 의 값을 참조하는 과정에서 문제가 있는지 한 번에 확인하기 위해서였다.
그리고 오류는 여전히 발생했다.
[ 2 ]
두 번째로 articleService 의 로직을 분석했다.
애초에 길게 작성된 코드가 아니라 articleRepository 로부터 게시글을 찾아오는 게 전부였다.
게시글을 찾지 못했을 때의 null 처리 또한 문제가 없었다.
[ 3 ]
내가 스프링 부트를 최신 버전으로 설정했는데, 혹시 Model 클래스에 무언가 변화가 있었나 싶어서 전부 다 지우고, @PathVariable Long id 를 제외하고 모든 코드를 다 지웠다.
그리고 게시글의 데이터를 Model 에 등록하지 않았기 때문에 show.html 에서도 게시글의 정보를 가져오지 않게끔 수정했다.
한 마디로, @PathVariable 어노테이션만 테스트했다.

바로 이렇게 말이다.
이때도 마찬가지로 에러 페이지가 반환되는 것을 보고 @PathVariable 이 기존에 알던 것과 다르게 작동한다고 생각했다.
ChatGPT 에게 자세히 질문해 봤으나, @PathVariable 의 value 값으로 매개변수의 이름을 명시해야 한다는 건 알아냈지만, 그 이유까지는 뾰족한 답을 얻지 못했다.
그래도 여기까지 진행했을 때 스프링 부트의 버전이 달라서 문법이 바뀌었다는 사실은 캐치할 수 있었지만, 정확히 어떻게 바뀐 건지 꼭 알아내고 싶었다.
내가 지난 번에 사용한 스프링 부트는 3.1 버전이고, 이번에 사용하고 있는 건 3.3.4 버전이므로, 공식 문서에서 그 사이의 패치 노트를 열람해 봤다.
그리고 그 해답은 바로 얻을 수 있었다.
문제 해결

공식 문서의 설명에 따르면, "바이트코드를 파싱하여 매개변수의 이름을 추론하는 기능을 더 이상 지원하지 않는다" 가 주된 요인이었다.
스프링 부트 3.2 버전 이후부터는 URL 변수를 어느 매개변수와 매핑할지 모르기 때문에 이름을 명시해줘야 한다는 것이다.
따라서 이를 해결하기 위해서는 설정에 -parameters 플래그를 추가하거나, @PathVariable 에 value 값으로 URL 변수의 이름을 명시해 줘야 한다.
바이트코드를 파싱한다는 건 무슨 뜻일까 ?
하지만 여기까지 읽어봐도 와닿지는 않았다.
아마도 바이트코드를 파싱한다는 개념을 잘 모르고, 매개변수의 이름이 떡하니 작성되어 있는데 왜 추론을 해야 한다는 건지 몰랐기 때문인 것 같다.
그래서 찾아본 바,
바이트코드(bytecode)란, Java 등의 고수준 언어를 컴파일하고 얻는 코드를 말한다.
자바 코드를 컴파일하면 기계어가 아니라 그 중간 단계인 바이트코드로 변환된다.
이때, 매개변수의 이름이 사라진다.
@PathVariable Long id 에서, Long 이라는 타입만 남고 id 라는 변수명은 사라지는 것이다.
그리고 파싱(parsing)이란, 코드의 구조를 분석하는 작업을 말한다.
바이트코드를 파싱함으로써 이름을 모르게 된 매개변수를 URL 변수 중에 어떤 것과 매핑할지 결정할 수 있게 되는 것이다.
과거에는 단순히 순서와 타입만 분석해서 매핑시켰다.
예를 들어,
@GetMapping("/{변수이름1}/{변수이름2}/{변수이름3}")
public void 메서드명(@PathVariable String 변수이름3,
@PathVariable String 변수이름1,
@PathVariable String 변수이름2) {}
이런 형태로 작성되어 있으면 단순히 순서대로 매핑되기 때문에
매개변수3 에는 {변수이름1},
매개변수1 에는 {변수이름2},
매개변수2에는 {변수이름3} 이 매핑된다.
그러나 -parameters 플래그를 사용하면 변수의 이름까지 정확히 추론해낼 수 있고, 그렇게 얻은 매개변수의 이름과 동일한 URL 변수명을 찾아서 묶는다.
물론 지금도 -parameters 플래그를 사용하면 변수명을 명시하지 않아도 되지만, 그조차도 없이 변수명을 명시해 주지 않으면 매핑에 실패하게 되는 것이다.