신비한 개발사전

@Param 및 @PathVariable의 파라미터 관련 에러 원인 및 해결방안 본문

Backend

@Param 및 @PathVariable의 파라미터 관련 에러 원인 및 해결방안

jbilee 2025. 5. 28. 20:47

아무런 문제 없던 코드를 리팩터링하는 도중에 갑자기 "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();
}

 

 

참고: