본문 바로가기
TIL

스프링부트 @ConfigurationProperties 매핑 오류(null)

by 긍고 2024. 10. 15.
반응형

얼마 전, 개인 프로젝트 진행 중 계정 관련 설정값을 application.yml 파일에 넣어둔 뒤 자바 객체로 받아와 사용하려고 한 적이 있었다. @Value 보다는 @ConfigurationProperties로 받아오면 객체형태로 받아올 수 있기 때문에 해당 방법을 통해 설정값을 받아오려고 했는데, 해당 값을 참조할 때마다 계속해서 NPE가 발생했다. 오늘은 해당 이슈에 대한 내용을 공유하려고 한다.

 

문제 상황


이슈의 원인을 공유하기 전에 먼저, 어떤 상황에서 발생했는지를 공유하려고 한다. 나는 아래와 같이 yml 파일에 계정 정보 리스트를 넣어두었다.

property:
  accounts:
    - name: test1
      password: pw1
    - name: test2
      password: pw2

 

그 뒤 name, password를 Account라는 객체로 받기 위해 선언한 뒤 Property라는 객체에 이 값들을 매핑하려 했다.

public class Account {
    private String name;
    private String password;
    // getters and setters
}


@ConfigurationProperties(prefix = "property")
public class Property {
    private List<Account> list; 
    // getters and setters
}

 

Property 키 내부의 Account들을 list라는 변수로 받아와 저장후에 사용하려고 하니, 의도와는 다르게 해당 변수에는 null이 들어가 있는 것을 확인할 수 있었다. 즉, 어노테이션을 통한 매핑이 제대로 이루어지지 않았다.

 

문제의 원인


null이 들어가는 원인을 찾기 위해 여러 부분을 점검했다. 설정값에 들여 쓰기, 오타 등의 오류는 없는지, 어노테이션에 값을 잘못 주었는지, Account 객체의 필드명에 오타가 있는지 등을 점검했으나, 그 어느 것도 원인이 아니었다. 그러던 와중 @ConfigurationProperties에 대한 공식 문서를 보다가 아래와 같은 문구를 보게 되었다.

 

스프링 부트의 @ConfigurationProperties는 YAML 또는 properties 파일과 클래스 간의 변수명 매칭을 통해 값을 바인딩합니다. 
YAML 파일의 계층 구조에 맞추어 클래스 필드 이름이 정확하게 일치해야만 값이 매핑됩니다. 만약 변수명이 다르거나 오타가 있을 경우 null이 반환됩니다.

 

 

이에 따르면 YAML 파일에서 property.accounts로 정의된 값을 클래스에서 accounts가 아닌 다른 이름(list)로 받으려 했기 때문에, 스프링은 해당 값을 찾을 수 없어 바인딩에 실패하게 되었고, 해당 값은 null로 들어가게 된 것이다.

 

생각보다 너무 간단한 이유라서 허무하긴 했지만, 한 편으로는 어노테이션을 사용할 때 편하다고 막 사용할 것이 아니라 사용법을 잘 숙지하고 사용해야겠다는 생각이 들었다. 아래와 같이 수정하면 올바르게 매핑이 되는 것을 확인할 수 있었다.

public class Account {
    private String name;
    private String password;
    // getters and setters
}


@ConfigurationProperties(prefix = "property")
public class Property {
    private List<Account> accounts; // yml 파일의 키값과 일치
    // getters and setters
}

 

매핑 실수를 방지하기 위한 방법


필수 값 바인딩 설정하기

스프링 부트에서는 @ConfigurationProperties와 함께 @Validated 어노테이션을 사용하여 필수 값의 누락 여부를 검증할 수 있기 때문에 아래와 같이 사용하면 실수를 방지할 수 있다.

@ConfigurationProperties(prefix = "property")
@Validated
public class Property {
    @NotNull
    private List<Account> accounts;
    // getters and setters
}

테스트 코드 작성하기

위와 같은 여러 부가 기능들을 사용하는것도 좋지만, 가장 기본적인 테스트코드를 작성해서 확인하는 습관을 들이는 것도 좋다.

@Test
public void testPropertyBinding() {
    assertNotNull(property.getAccounts());  // Null 여부 검증
    assertEquals(2, property.getAccounts().size());
}

 

정리


@ConfigurationProperties를 사용해 스프링 부트 애플리케이션에서 설정 값을 바인딩할 때는 YAML 파일의 키와 클래스 변수명이 정확하게 일치해야 한다는 점이 중요하다. 조금만 방심해도 변수명을 다르게 작성하여 값이 null로 들어오는 오류를 경험할 수 있고 상당한 시간을 소요할 수 있다..😥 이러한 실수를 피하려면 YAML 파일과 클래스 간의 구조를 꼼꼼히 맞추고, 로그나 테스트 코드를 활용해 문제가 발생하기 전에 오류를 발견하는 것이 좋을 것 같다.

댓글