Spring Configuration 의 Cannot resolve configuration property 문제
spring에서 제공하는 configuration 말고도 따로 properties/yml의 configuration을 추가해서 쓸때가 많습니다.
Configuration Property 내부의 Nested Property, 즉 중첩된 Property가 있는 경우에는 Spring 에서 그 데이터 타입에 대한 정의를 하라고 하는데요.
아래 사진을 보면 밝게 표시된 property 입니다.
특히 개발 IDE 중 인텔리제이를 쓰시는분들중 저처럼 이게 거슬리는 분들이 많을 것 같습니다.
일단 이걸 재현하기 위해 예제를 보시게 되면
property model 만들기
yml에서 설정이 바인딩 될 모델입니다.
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class SomeProperty {
private String someName;
private boolean isEnabled;
private SomeNestedProperty someNestedProperty;
}
SomeNestedProperty
라는 타입이 있는데 설정 안의 설정 필드로 쓰기 위해 만든 Object 입니다.
아래처럼 간단하게 세팅했습니다.
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.util.List;
@Getter
@Setter
@ToString
public class SomeNestedProperty {
private String someNestedName;
private List<String> someNestedList;
}
그리고 이걸 Configuration 에서 주입하게 되면
configuration
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.Assert;
import sunghs.springexample.nestedconfiguration.SomeProperty;
@Slf4j
@Configuration
public class SomeConfiguration implements InitializingBean {
@Bean
@ConfigurationProperties("some")
public SomeProperty someProperty() {
return new SomeProperty();
}
@Override
public void afterPropertiesSet() {
SomeProperty someProperty = someProperty();
Assert.notNull(someProperty, "someProperty must not be null");
log.info("someProperty : {}", someProperty);
}
}
대강 이런식으로 사용할 수 있게 될 것 인데요,
@ConfigurationProperties("some")
이니 application.yml에 작성해보겠습니다.
application.yml
some:
some-name: test
is-enabled: true
some-nested-property:
some-nested-name: nested-test
some-nested-list: a,b,c,e,d
설정 객체(SomeProperty) 안의 객체(SomeNestedProperty)에 바인딩이 되는지 보겠습니다.
정확히 됩니다. 하지만 인텔리제이에는 아래 사진처럼 저 속성에 대해 타입을 알아낼 수 없다고 나옵니다.
이걸 해결하는 방법에는 두가지가 있는데, 첫번째 방법은 많이 알려졌는데 두번째 방법은 많이 안알려져 있는것 같습니다.
1. spring-configuration-metadata.json 에 직접 쓰기
src/main/resources/META-INF/spring-configuration-metadata.json 위치에 key-value에 대한 정의를 만들라고 합니다.
예를들면 아래 처럼 작성하면 됩니다.
{
"properties": [
{
"name": "key",
"type": "java.lang.String"
},
{
...
},
...
]
}
근데 1번 방법은 굉장히 번거롭고, @ConfigurationProperties
를 쓰게 되면 원래 자동 생성되서 인텔리제이 같은 IDE에서 cannot resolve... 가 뜨지 않는 것인데
NestedProperty를 위해 하나하나 쓰고 있기가 힘듭니다. 그래서 아래 두번째 방법으로 해결 할 수 있습니다.
2. @NestedConfigurationProperty
이게 잘 안알려진 방법 같은데, 어노테이션 이름부터가 중첩 설정프로퍼티에 사용하는 거라고 써 있습니다.
이걸 아래처럼 세팅하게 되면
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
@Getter
@Setter
@ToString
public class SomeProperty {
private String someName;
private boolean isEnabled;
@NestedConfigurationProperty
private SomeNestedProperty someNestedProperty;
}
그 후 compile 진행 시 yml에서 cannot resolve.. 메시지가 사라집니다.
어노테이션을 보고 내부의 SomeNestedProperty 객체의 metadata.json을 자동으로 작성 한 걸 알 수 있습니다.
NestedConfigurationProperty 없을 때 metadata.json
NestedConfigurationProperty 있을 때 metadata.json
metadata.json에 자동으로 생성 된 게 보이네요.
결론
크게 중요한 건 아니긴 한데, 실제 resolve 되지 않더라도 자동 바인딩은 되나 저처럼 저런거 신경 거슬리는 분들은 NestedConfigurationProperty
어노테이션을 잘 쓰면 될 것 같습니다.
소스는 여기 있습니다.
github
'Framework' 카테고리의 다른 글
[Spring] 파라미터 바인딩을 해주는 HandlerMethodArgumentResolver (Webflux Version) (0) | 2022.06.20 |
---|---|
[Spring] 파라미터 바인딩을 해주는 HandlerMethodArgumentResolver (MVC Version) (0) | 2022.05.30 |
[Spring] 스프링 Conditional 어노테이션 조건 직접 만들기 (Custom Conditional) (0) | 2022.03.31 |
[Spring] JWT 사용 시 Spring Security Filter 흐름 분석 (0) | 2022.01.14 |
[Mybatis] mybatis 사용 시 xml, interface 경로가 일치해야 하는 문제 (1) | 2021.12.02 |
댓글