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

Jaehak Park님의 프로필 이미지

작성한 질문수

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

요청 매핑

@PathVariable 변수명 같을때 생략시 오류 (빌드 설정을 gradle로 하면 해결되는 것 같습니다)

해결된 질문

작성

·

2.8K

·

수정됨

3

 

 

/**
 * PathVariable 사용
 * 변수명이 같으면 생략 가능
 * @PathVariable("userId") userId -> @PathVariable String userId
 */
@GetMapping("/mapping/{userId}")
public String mappingPath(@PathVariable ("userId") String data){
    log.info("mappingPath userId={}",data);
    return "ok";
}

 

다음 코드에서 영상에서 알려주신데로 변수명 중복시 생략하였을때

@GetMapping("/mapping/{userId}")
public String mappingPath(@PathVariable String userId){
    log.info("mappingPath userId={}",userId);
    return "ok";
}


아래와 같이 사용하였으니 실행시에 500에러가 뜹니다

{
    "timestamp": "2023-11-29T03:47:55.458+00:00",
    "status": 500,
    "error": "Internal Server Error",
    "path": "/mapping/userA"
}

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

답변 7

7

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

안녕하세요. Jaehak Park님 다음을 참고해주세요

자주하는 질문 링크: 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

Jaehak Park님의 프로필 이미지
Jaehak Park
질문자

직접 name속성을 추가하였을때는 잘됩니다

0

혹시 문제 해결에 도움이 될까 싶어 공유드립니다

build.gradle에 최신 버전으로 이니셜라이징 한 내용이 아래와 같고
증상이 재학님과 같아 헤매던 중

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

아래처럼 이전에 강의 수강시의 버전으로 아래와 같이 낮추어 실행해본 결과

name 속성 생략이 이전과 같이 잘 동작했습니다

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

공식문서를 아직 확인은 못해봤는데, 혹시 버전이 올라가면서 더 이상 생략을 허용하지 않는걸까요..?

저도 문서를 확인해보진 못했지만 아래 링크의 다른 수강생분 답변을 보면 3.2.0부터 변경사항이 발생한거 같네요 ^^

https://www.inflearn.com/questions/1087879/pathvariable-name-%EC%83%9D%EB%9E%B5-%EC%A7%88%EB%AC%B8-%EB%93%9C%EB%A6%BD%EB%8B%88%EB%8B%A4

0

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

안녕하세요. Jaehak Park님

코드를 살펴봐야 할 것 같아요.

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

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

https://bit.ly/3fX6ygx

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

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

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

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

감사합니다.

Jaehak Park님의 프로필 이미지
Jaehak Park
질문자

안녕하세요. 구글 드라이브로 링크 남겨드립니다.

확인해주셔서 감사합니다!!


https://drive.google.com/drive/folders/1ugGV8aXmF4J75DfLke1zihub5wUWmJKl?usp=sharing

Jaehak Park님의 프로필 이미지
Jaehak Park
질문자

안녕하세요 영한님!

여러가지 방법으로 해본 결과

settings - gradle에서 intellij build and run을 설정을 default인 gradle로 바꾸었더니 정상작동하는 것 같습니다.

정확한 이유는 모르겠지만 gradle로는 인식이 가능한데 intellij에서는 인식이 안되는 것 같네요 ㅜㅜ

0

Jaehak Park님의 프로필 이미지
Jaehak Park
질문자

마지막으로 말씀해주신 build gradle에 추가후 돌려봤는데도 오류가 발생하네요ㅜㅜ

스크린샷 2023-11-29 153451.png

0

Jaehak Park님의 프로필 이미지
Jaehak Park
질문자

  1. name 속성 그대로 부여해 사용시스크린샷 2023-11-29 152722.png

     

  2. name 속성 생략하여 사용시

     

    스크린샷 2023-11-29 152842.pngJava HotSpot(TM) 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended

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

     

     

  1. oracle 17

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

build.gradle 맨 마지막 줄에 위 코드도 추가하여 확인해주세요 :)

Jaehak Park님의 프로필 이미지
Jaehak Park
질문자

위 코드 추가하여 확인하였는데도 같습니다
어디가 문제인지 감도 안오네요..

@PathVariable과 비슷한 맥락으로 작동하는 @RequestParam의 경우에도 똑같은 증상이 나옵니다

 

0

안녕하세요. Jaehak Park님, 공식 서포터즈 OMG입니다.

Pathvariable의 name 속성을 추가했을 때와 추가하지 않았을 때 각각

아래의 테스트 코드를 복사하여 실행해서 테스트 성공하는지 실패하는지 결과를 공유해주세요 :)

package hello.springmvc;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@AutoConfigureMockMvc
class SpringmvcApplicationTests {

   @Autowired
   MockMvc mockMvc;
   @Test
   void contextLoads() {
   }

   @Test
   void test() throws Exception{
      mockMvc.perform(get("/mapping/userA"))
            .andExpect(status().isOk());
   }
}

image

그리고

 

build.gradle 맨 마지막 줄에 아래 코드를 추가했을 때의 결과도 공유해주시겠어요?

 

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

 

마지막으로 어떤 JDK를 사용하는지 버전과 벤더명도 알려주세요 ^^

ex) oracle 11

 

감사합니다.