본문 바로가기
SpringBoot

[Spring Boot][Error] @value annotation always return null

by 청양호박이 2021. 4. 12.

Spring Boot로 프로그래밍을 하다보면, 고정적으로 사용할 값들을... (하지만 가끔은 변경할 가능성도 있는 값이 되겠네요) 한곳에 모아놓고 사용하고 싶어질 때가 있습니다. 예를들면 접속할 URL, OAuth의 Client ID 등이 되겠습니다. 이를 모아서 사용하는 이유는 명확하게 있습니다.

 

공통적으로 사용하는 값이 중앙에서 관리를 안 할 경우, 소스의 군데군데 상수로 박혀있을 것 입니다. 하지만 언젠가는 해당 값이 변경될 경우도 있을텐데... 이 경우에 큰 공사가 발생할 수 있습니다. 따라서 한곳에 이렇한 값들을 모아놓고 소스에서는 변수로 불러와 사용한다면, 나중에 상수라고 생각한 값이 바뀌더라도 전체 코드에서 해당 변수를 사용한 모든 위치를 바꾸는 대신에... 이러한 상수를 모아논 위치의 내용만 바꾸면 해결이 될 수 있습니다. 

 

Spring Boot에서는 해당 역할을 하는 곳이 바로 application.propoties 혹은 application.yml이 되겠습니다. 기존에 해당 yml 파일에 아래와 같이 DataSource나 실행 port등을 지정하는데 사용했었습니다. 

 

[application.yml]

spring:
  datasource:
    hikari:
      main:
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbcUrl: jdbc:mysql://localhost:3306/[개별설정]
        username: [id]
        password: [password]

server:
  port: 8888
  servlet:
    session:
      timeout: 30

 

해당 파일은 이런역할도 하지만, 프로그램 내에서 공통으로 사용되는 상수에 대해서 지정하고 원하는 위치에서 불러와 사용할 수 있습니다. 예를 들어서, 저는 Google OAuth를 구성하다가 해당 기능을 사용하였기 때문에 관련해서 작성해 보겠습니다. 

 

[application.yml 추가]

oauth:
  google:
    clientId: 1413874402xxxxxx....xxx.apps.googleusercontent.com

다음과 같이 OAuth를 위한 clientId를 관련한 상수로 application.yml에 작성했습니다. 이제 이 값을 원하는 class위치에서 불러와서 사용해야 합니다. 이를 위한 방법은 @value annotation을 활용하는 것 입니다. 원하는 코드에서 아래와 같이 추가해 줍니다.

 

[원하는 코드 내 변수정의부분 추가]

@Value("${oauth.google.clientId:'100'}")
private String clientId;

해당 annotation은 application.yml의 파일내에서 다음의 경로에 기재되어 있는 값을 clientId라는 변수에 넣어주고, 해당 값이 없을 경우 default값으로 100을 넣어줘!! 라는 의미입니다. 다음의 경로는 ${oauth.google.clientId} 라고 정의한 경로입니다. 이 경로는 yml에 최근에 추가한 경로와 같습니다. 

 

실행을 해서 불러온 값을 바로 출력해 보면...

INFO 17064 --- [nio-8888-exec-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
INFO 17064 --- [nio-8888-exec-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
idToken : 1413874402xxxxxx....xxx.apps.googleusercontent.com

정상적으로 가져옴을 확인할 수 있습니다.

 

 

발견된 문제 해결 방법


이렇게 구현하는 도중... 저는 1가지 공통된 결과에 대해서 2가지 문제를 발견해서 해결했습니다. 이에 대해서 해결했던 내용을 적어보겠습니다. 

 

[Error1 - another library import] 

 

@value annotation을 사용하려면, springframework의 기본 library에서 제공하는 beans.factory의 annotation.Value를 import해줘야 합니다. 하지만 어떠한 상황에서는 다른 library에서 동일한 이름으로 Value를 제공하는 경우가 발생할 수 있습니다. 

 

예를 들어서, com.google.api.client.util.Value의 경우가 그렇습니다. google api library에서 제공하는 Value를 import할 경우는 @value annotation을 통한 application.yml의 접근이 불가능하기 때문에 항상 결과는 null이 발생하게 됩니다.

 

(@value annotation always return null. So you must check that the library is correctly imported always.)

 

다음과 같이 2개중에 하나를 선택하라고 친절하게 eclipse가 알려주기도 합니다. 

import com.google.api.client.util.Value vs import org.springframework.beans.factory.annotation.Value 무의식적으로 엔터를 막 누르는 경우에는 한참 null이 return되는 상황에 고민하다가... 발견하고 좌절하는 경우도 있으니까요.

 

[Error2 - put it in the static value] 

 

@value annotation을 통해서 정상적으로 값을 application.yml로 부터 가져와서... static 변수에 넣을 경우 역시나 항상 return null을 발생시킵니다. 예를들면, 아래와 같습니다. (기존의 코드를 활용해보면....)

 

[변수정의부분 static 지정 - only return null]

@Value("${oauth.google.clientId:'100'}")
private static String clientId;

정적변수를 꼭 사용해야 한다면... 바로 application.yml을 통해서 가져온 값을 주입할 수 없고, 다른 방법을 사용해야 합니다. 우선 변수를 선언하고 setter를 @value annotation에 기술해 주는 방법입니다.

 

[변수정의부분 static 지정 - 수정]

	private static String clientId;
	
	@Value("${oauth.google.clientId:'100'}")
	private void setClientId(String temp) {
		clientId = temp;
	}

이렇게 구성하면 정상적으로 동작합니다.

INFO 29024 --- [nio-8888-exec-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
INFO 29024 --- [nio-8888-exec-1] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
idToken : 1413874402xxxxxx....xxx.apps.googleusercontent.com

그럼 항상 즐거운 코딩 되세요~~

 

- Ayotera Lab -

댓글