在 Spring Boot 中将 YAML 转换成对象列表

1、概览

本文将带你了解如何在 YAML 中定义列表,以及如何在 Spring Boot 中把 YAML 列表映射为 Java List 对象。

2、回顾一下 YAML 中的列表

简而言之,YAML 是一种人类可读的数据序列化标准,为编写配置文件提供了一种简洁明了的方法。YAML 的优点在于它支持多种数据类型,如 ListMap 和标量(Scalar)类型。

YAML 列表中的元素使用 - 字符定义,它们的缩进级别相同:

yamlconfig:
  list:
    - item1
    - item2
    - item3
    - item4

相比之下,在 properties 中定义列表则使用的是索引值:

yamlconfig.list[0]=item1
yamlconfig.list[1]=item2
yamlconfig.list[2]=item3
yamlconfig.list[3]=item4

与 properties 文件相比,YAML 的分层性质大大提高了可读性。YAML 的另一个功能是可以为不同的 Spring Profile 定义不同的属性。从 Boot 2.4.0 版开始,properties 文件也可以这样做。

Spring Boot 为 YAML 配置提供了开箱即用的支持。根据设计,Spring Boot 会在启动时从 application.yml 中加载配置属性,无需任何额外工作。

3、将 YAML 列表绑定至简单的 List

Spring Boot 提供了 @ConfigurationProperties 注解,以简化将外部配置数据映射到对象模型的逻辑。

接下来看看如何使用 @ConfigurationProperties 将 YAML 列表绑定到 List<Object> 中。

首先在 application.yml 中定义一个简单的列表:

application:
  profiles:
    - dev
    - test
    - prod
    - 1
    - 2

然后,创建一个简单的 ApplicationProps POJO,用于将 YAML 列表绑定到 List<Object>

@Component
@ConfigurationProperties(prefix = "application")
public class ApplicationProps {

    private List<Object> profiles;
    
    // get、set 方法

}

ApplicationProps 类需要用 @ConfigurationProperties 来装饰,表示将带有指定前缀的所有 YAML 属性映射到 ApplicationProps 对象。

要绑定 profiles 列表,只需定义一个 List 类型的字段,剩下的就交给 @ConfigurationProperties 注解来处理。

使用 @ComponentApplicationProps 类注册为普通的 Spring Bean。因此,可以像其他 Spring Bean 一样将其注入到其他类中。

最后,将 ApplicationProps Bean 注入测试类,并验证配置文件 YAML 列表是否被正确注入为 List<Object>*

@ExtendWith(SpringExtension.class)
@ContextConfiguration(initializers = ConfigDataApplicationContextInitializer.class)
@EnableConfigurationProperties(value = ApplicationProps.class)
class YamlSimpleListUnitTest {
 
    @Autowired
    private ApplicationProps applicationProps;
 
    @Test
    public void whenYamlList_thenLoadSimpleList() {
        assertThat(applicationProps.getProfiles().get(0)).isEqualTo("dev");
        assertThat(applicationProps.getProfiles().get(4).getClass()).isEqualTo(Integer.class);
        assertThat(applicationProps.getProfiles().size()).isEqualTo(5);
    }
}

4、将 YAML 列表绑定到复杂的 List

来看看如何将嵌套的 YAML 列表注入到复杂结构的 List 中。

首先,在 application.yml 中添加一些嵌套列表:

application:
  // ...
  props: 
    -
      name: YamlList
      url: http://yamllist.dev
      description: Mapping list in Yaml to list of objects in Spring Boot
    -
      ip: 10.10.10.10
      port: 8091
    -
      email: support@yamllist.dev
      contact: http://yamllist.dev/contact
  users:
    -
      username: admin
      password: admin@10@
      roles:
        - READ
        - WRITE
        - VIEW
        - DELETE
    -
      username: guest
      password: guest@01
      roles:
        - VIEW

本例中,我们要把 props 属性绑定到 List<Map<String, Object>> 中,把 users 映射到 User 对象的 List 中。

由于 props 条目的每个元素都拥有不同的 Key,因此可以将其注入为 List<Map<String, Object>>表。

然而,在 users 列表下,所有项目的 Key 都相同,因此为了简化映射,可以创建一个专门的 User 类,将 Key 封装为字段:

public class ApplicationProps {
    
    // ...

    private List<Map<String, Object>> props;
    private List<User> users;
    
    // get / set 方法

    public static class User {

        private String username;
        private String password;
        private List<String> roles;

         // get / set 方法

    }
}

现在,来验证嵌套的 YAML 列表是否已正确映射:

@ExtendWith(SpringExtension.class)
@ContextConfiguration(initializers = ConfigDataApplicationContextInitializer.class)
@EnableConfigurationProperties(value = ApplicationProps.class)
class YamlComplexListsUnitTest {
 
    @Autowired
    private ApplicationProps applicationProps;
 
    @Test
    public void whenYamlNestedLists_thenLoadComplexLists() {
        assertThat(applicationProps.getUsers().get(0).getPassword()).isEqualTo("admin@10@");
        assertThat(applicationProps.getProps().get(0).get("name")).isEqualTo("YamlList");
        assertThat(applicationProps.getProps().get(1).get("port").getClass()).isEqualTo(Integer.class);
    }

}

5、总结

本文介绍了如何把 YAML 中的列表映射为 Java List,以及如何在 Spring Boot 中自动把属性绑定到 POJO 类。


Ref:https://www.baeldung.com/spring-boot-yaml-list