신비한 개발사전
@Param 및 @PathVariable의 파라미터 관련 에러 원인 및 해결방안 본문
아무런 문제 없던 코드를 리팩터링하는 도중에 갑자기 "For queries with named parameters you need to provide names for method parameters" 오류가 발생하기 시작했다..
아래는 오류가 발생한 코드다. 해당 코드는 잘 동작함을 확인했었고 이후엔 수정한 적도 없는데, 다른 변동사항을 확인하기 위해 테스트를 돌려보니 동작하지 않는다. 어디가 잘못되었길래 없던 오류가 나타났을까?
@Query("""
SELECT t
FROM Theme t
JOIN Reservation r ON r.details.theme = t
WHERE r.details.date >= :from AND r.details.date < :to
GROUP BY t
ORDER BY COUNT(r.id) DESC
""")
List<Theme> findTopThemes(LocalDate from, LocalDate to, PageRequest pageable);
해결책부터 언급하자면, JPQL을 쓸 때 콜론(:)으로 주입하는 변수값은 @Param을 매개변수에 붙여줘야 한다. 하지만 이전까지는 안 붙여도 제대로 동작했어서 혼란스럽기만 했다.
잘 생각해보니 유일하게 달라진 점이 하나 있었는데, 바로 개발 환경이었다.
당시에 맥북과 윈도우 데스크탑을 번갈아가면서 같은 레포에 작업을 하고 있었는데, 맥북 IDE에는 빌더가 Gradle로 설정되어 있었고 윈도우에는 IntelliJ를 빌더로 쓰고 있었다.
💥 오류는 IntelliJ로 빌드한 경우에만 발생하고 있었다.
이 문제를 깨닫는 과정에서 또다른 오류를 접했었는데, 이것 또한 빌드 툴이 IntelliJ일 때만 발생하는 오류였다. 아래 문제 코드에서 볼 수 있듯, @PathVariable 애노테이션을 쓸 때 변수명 매핑을 누락한게 원인이었다.
@DeleteMapping("/waitings/{id}")
public ResponseEntity<Void> deleteWaiting(@PathVariable final Long id, Member member) {
waitingService.deleteWaiting(id, member.getId());
return ResponseEntity.noContent().build();
}
@PathVariable에 매핑할 변수명을 전달하지 않을 경우엔 아래 오류가 발생한다.
java.lang.IllegalArgumentException: Name for argument of type [java.lang.String] not specified, and parameter name information not available via reflection. Ensure that the compiler uses the '-parameters' flag.
오류 메세지를 보면 컴파일러에게 -parameters 플래그를 설정해서 해결할 수도 있다고 한다.
찾아보니 컴파일러 설정을 통해, Gradle로 빌드하지 않아도 위 코드를 문제 없이 동작하게 만들 수 있다. (이 해결 방식은 JPQL에도 동일하게 활용할 수 있다) IDE 설정에서 Build, Execution, Deployment > Compiler > Java Compiler 메뉴로 들어가 "Additional command line parameters" 필드에 "-parameters" 값만 넣어주면 된다.
-parameters 플래그 없이 문제를 해결하고자 한다면 JPQL에는 @Param 애노테이션을, @PathVariable에는 변수명을 전달하면 된다.
// JPQL 사용 시 @Param을 전달하자
@Query("""
SELECT t
FROM Theme t
JOIN Reservation r ON r.details.theme = t
WHERE r.details.date >= :from AND r.details.date < :to
GROUP BY t
ORDER BY COUNT(r.id) DESC
""")
List<Theme> findTopThemes(@Param("from") LocalDate from, @Param("to") LocalDate to, PageRequest pageable);
// @PathVariable 사용 시 value 속성을 전달하자
@DeleteMapping("/waitings/{id}")
public ResponseEntity<Void> deleteWaiting(@PathVariable("id") final Long id, Member member) {
waitingService.deleteWaiting(id, member.getId());
return ResponseEntity.noContent().build();
}
참고:
'Backend' 카테고리의 다른 글
Spring REST Docs로 생성한 API 문서의 배포 문제를 해결한 과정 (0) | 2025.06.09 |
---|---|
Spring REST Docs 적용기 (0) | 2025.06.07 |
@Embedded, @Embeddable로 객체지향적인 JPA 엔티티 설계하기 (0) | 2025.05.25 |
@Transactional 유무에 의한 로직 동작 차이 (0) | 2025.05.22 |
RestTemplate vs RestClient (0) | 2025.05.21 |