인프런 커뮤니티 질문&답변

co-account님의 프로필 이미지
co-account

작성한 질문수

스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술

상품 등록 폼

@PathVariable name 생략 질문 드립니다.

해결된 질문

작성

·

5.7K

8

학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.

1. 강의 내용과 관련된 질문을 남겨주세요.
2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.
(자주 하는 질문 링크: https://bit.ly/3fX6ygx)
3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.
(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)

질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.
=========================================
[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? (예/아니오)
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)
3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)

[질문 내용]
여기에 질문 내용을 남겨주세요.

@GetMapping("/{itemId}")
public String item(@PathVariable("itemId") Long itemId, Model model) {
Item item = itemRepository.findById(itemId);
model.addAttribute("item", item);
return "basic/item";
}

제가 알기론 Mapping 의 경로와 변수명이 같다면 name을 생략 가능한걸로 알아 원래 예제에선 PathVariable 뒤에 ("itemId") 를 생략하여도 잘 작동하지만, 따라해보니 name을 생략하면 아래와 같은 오류가 발생합니다.
java.lang.IllegalArgumentException: Name for argument of type [java.lang.Long] not specified, and parameter name information not found in class file either

왜 이런걸까요>?

답변 2

9

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. co-account님 다음을 참고해주세요

그리고 스프링 부트 3.2를 사용하시는 것을 권장합니다. 🙂

자주하는 질문 링크: https://docs.google.com/document/d/1j0jcJ9EoXMGzwAA2H0b9TOvRtpwlxI5Dtn3sRtuXQas/edit#heading=h.b1yk4ued1pxo

주의! 스프링 부트 3.2 파라미터 이름 인식 문제

스프링 부트 3.2부터 자바 컴파일러에 -parameters 옵션을 넣어주어야 애노테이션의 이름을 생략할 수 있다.

발생하는 예외

java.lang.IllegalArgumentException: Name for argument of type [java.lang.String] not specified, and parameter name information not found in class file either.

 

주로 다음 두 애노테이션에서 문제가 발생한다.

@RequestParam, @PathVariable

@RequestParam 관련

//애노테이션에 username이라는 이름이 명확하게 있다. 문제 없이 작동한다.

@RequestMapping("/request")

public String request(@RequestParam("username") String username) {

   ...

}

//애노테이션에 이름이 없다. -parameters 옵션 필요

@RequestMapping("/request")

public String request(@RequestParam String username) {

   ...

}

//애노테이션도 없고 이름도 없다. -parameters 옵션 필요

@RequestMapping("/request")

public String request(String username) {

   ...

}

 

@PathVariable 관련

//애노테이션에 userId라는 이름이 명확하게 있다. 문제 없이 작동한다.

public String mappingPath(@PathVariable("userId") String userId) {

    ...

}

//애노테이션에 이름이 없다. -parameters 옵션 필요

@RequestMapping("/request")

public String request(@RequestParam String username) {

   ...

}

 

해결 방안1

애노테이션에 이름을 생략하지 않고 다음과 같이 이름을 항상 적어준다.

@RequestParam("username") String username

@PathVariable("userId") String userId

 

해결 방안2

컴파일 시점에 -parameters 옵션 적용

1. IntelliJ IDEA에서 File -> Settings를 연다. (Mac은 IntelliJ IDEA -> Settings)

2. Build, Execution, Deployment → Compiler → Java Compiler로 이동한다.

3. Additional command line parameters라는 항목에 다음을 추가한다.

-parameters

4. out 폴더를 삭제하고 다시 실행한다. 꼭 out 폴더를 삭제해야 다시 컴파일이 일어난다.

 

해결 방안3(권장)

Gradle을 사용해서 빌드하고 실행한다.

 

문제 원인

참고로 이 문제는 Build, Execution, Deployment -> Build Tools -> Gradle에서

Build and run using를 IntelliJ IDEA로 선택한 경우에만 발생한다.

Gradle로 선택한 경우에는 Gradle이 컴파일 시점에 해당 옵션을 자동으로 적용해준다.

자바를 컴파일할 때 매개변수 이름을 읽을 수 있도록 남겨두어야 사용할 수 있다. 컴파일 시점에 -parameters 옵션을 사용하면 매개변수 이름을 사용할 수 있게 남겨둔다.

스프링 부트 3.2 전까지는 바이트코드를 파싱해서 매개변수 이름을 추론하려고 시도했다. 하지만 스프링 부트 3.2 부터는 이런 시도를 하지 않는다.

 

감사합니다.

안녕하세요 영한님

설명해주신 해결방안들 잘 읽어 보았는데

해결방안 1을 다른 해결방안보다 권장해주신 이유가 궁금합니다!!

 

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. villa95님 해결3을 권장하도록 변경했습니다.

해결1이 좋은 이유는 자바 컴파일 상황과 무관하게 항상 작동하기 때문입니다.

그런데 스프링 3.2에서 관련된 이슈가 이것 뿐만 아니라 너무 많아서 해결 3을 사용하는 것을 권장합니다.

감사합니다.

0

안녕하세요. co-account님, 공식 서포터즈 코즈위버입니다.

도움을 드리고 싶지만 질문 내용만으로는 답변을 드리기 어렵습니다.

실제 동작하는 전체 프로젝트를 압축해서 구글 드라이브로 공유해서 링크를 남겨주세요.

구글 드라이브 업로드 방법은 다음을 참고해주세요.

https://bit.ly/3fX6ygx


주의: 업로드시 링크에 있는 권한 문제 꼭 확인해주세요


추가로 다음 내용도 코멘트 부탁드립니다.

1. 문제 영역을 실행할 수 있는 방법

2. 문제가 어떻게 나타나는지에 대한 상세한 설명

감사합니다.

co-account님의 프로필 이미지
co-account
질문자

https://drive.google.com/file/d/1UFCLpIaWds7UPQoe0BT1o2kC66r1Be7z/view?usp=sharing

  1. Spring boot 로 ItemServiceApplication 실행 후 http://localhost:8080/basic/items 에서 상품명 혹은 ID 클릭.

  2. java.lang.IllegalArgumentException: Name for argument of type [java.lang.Long] not specified, and parameter name information not found in class file either 에러 발생

settings - gradle에서 build and run 설정이 gradle이실까요?

제가 겪은 문제랑 같으신 것 같네요

co-account님의 프로필 이미지
co-account
질문자

원래는 세팅이 IntelliJ IDEA 였는데 Gradle 로 바꾸니 해결됐네요. 감사합니다. 혹시 IntelliJ IDEA 로 세팅하면 왜 안되는지 아시나요?

다행입니다

저도 이부분이 왜 안되는진 모르겠으나

intellij에서는 pathvariable 어노테이션을 시용하였을때 컴파일시 자동으로 인식하지 못하는 문제가 있는것 같네요

https://github.com/spring-projects/spring-boot/issues/38536

https://github.com/spring-projects/spring-framework/wiki/Upgrading-to-Spring-Framework-6.x#parameter-name-retention

위의 두 링크 들어가 보시면 스프링 부트 3.2.0부터 컴파일 argument를 추가해야 한다고 하네요.

저는 그냥 build.gradle 파일의

 

plugins { 
    id 'java' 
    id 'org.springframework.boot' version '3.1.5' 
    id 'io.spring.dependency-management' version '1.1.4'
}

 

스프링 부트 버전을 3.1.5로 수정해서 컴파일했더니 해결되었습니다.

조금 더 찾아보니 스프링 부트 3.2.0부터 -parameters 라는 자바 컴파일 옵션을 설정해야 파라미터 이름을 생략할 수 있나 보네요.

intellij idea로 build 시 -parameters 옵션이 설정되어 있지 않기 때문에 안되는 것이고

gradle로 build 시에는 -parameters 옵션이 자동 설정되어서 따로 build.gradle에 따로 등록하지 않아도 되는 것 같습니다.

혹시 -parameter 옵션이라는게 아래의 코드 말씀하시는걸까요??

제가 아래코드 build.gradle에 추가하였을때에도 정상작동을 하지 않아서 그러는데 확인한번 부탁드려도 될까요?

 

compileJava { options.compilerArgs << '-parameters' }

 

 

build and run 이 intellij idea로 설정되어 있으면 build.gradle의 컴파일 옵션이 적용이 안되더라고요

build and run 을 gradle로 해야 적용이 되는데 gradle 2.x 버전 이후부터 -parameter 옵션이 자동 적용되어 있어서 위의 옵션을 추가하지 않아도 되네요.

그럼 결국 build를 gradle로 하거나

말씀해주신 것 처럼 부트버전을 낮추거나인 거네요? .. 감사합니다

build를 gradle로 하니까 영한 님이 말씀하신 것처럼 꽤 느려서 부트 버전을 그냥 낮추는 게 마음 편할 것 같아요 :)

co-account님의 프로필 이미지
co-account

작성한 질문수

질문하기