«1. Обзор

В этом коротком руководстве мы подробно рассмотрим, как преобразовать список YAML в список в Spring Boot.

Сначала мы начнем с некоторых сведений о том, как определять списки в YAML. Затем мы копнем глубже, чтобы увидеть, как связать списки YAML со списками объектов.

2. Краткий обзор списков в YAML

Короче говоря, YAML — это удобочитаемый стандарт сериализации данных, который обеспечивает краткий и понятный способ написания файлов конфигурации. Преимущество YAML заключается в том, что он поддерживает несколько типов данных, таких как списки, карты и скалярные типы.

Элементы в списке YAML определяются с помощью символа «-», и все они имеют одинаковый уровень отступа:

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

Для сравнения, эквивалент на основе свойств использует индексы:

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

Дополнительные примеры можно найти в нашей статье о том, как определять списки и карты с помощью файлов YAML и свойств.

Фактически, иерархическая природа YAML значительно улучшает читабельность по сравнению с файлами свойств. Еще одна интересная особенность YAML — возможность определять разные свойства для разных профилей Spring. Начиная с версии Boot 2.4.0, это также возможно для файлов свойств.

Стоит отметить, что Spring Boot предоставляет встроенную поддержку конфигурации YAML. По замыслу Spring Boot загружает свойства конфигурации из application.yml при запуске без каких-либо дополнительных действий.

3. Привязка списка YAML к простому списку объектов

Spring Boot предоставляет аннотацию @ConfigurationProperties для упрощения логики отображения внешних данных конфигурации в объектную модель.

В этом разделе мы будем использовать @ConfigurationProperties для привязки списка YAML к List\u003cObject\u003e.

Мы начнем с определения простого списка в application.yml:

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

Затем мы создадим простой POJO ApplicationProps для хранения логики привязки нашего списка YAML к списку объектов:

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

    private List<Object> profiles;
    
    // getter and setter

}

~ ~~ Класс ApplicationProps должен быть украшен @ConfigurationProperties, чтобы выразить намерение сопоставить все свойства YAML с указанным префиксом с объектом ApplicationProps.

Чтобы связать список профилей, нам просто нужно определить поле типа List, а аннотация @ConfigurationProperties позаботится обо всем остальном.

Обратите внимание, что мы регистрируем класс ApplicationProps как обычный bean-компонент Spring, используя @Component. В результате мы можем внедрить его в другие классы так же, как и любой другой компонент Spring.

Наконец, мы вставляем bean-компонент ApplicationProps в тестовый класс и проверяем, правильно ли вводится список YAML наших профилей как List\u003cObject\u003e:

@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 к сложным спискам

Теперь, давайте углубимся и посмотрим, как внедрить вложенные списки YAML в сложные структурированные списки.

Во-первых, давайте добавим несколько вложенных списков в 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: [email protected]
      contact: http://yamllist.dev/contact
  users:
    -
      username: admin
      password: [email protected]@
      roles:
        - READ
        - WRITE
        - VIEW
        - DELETE
    -
      username: guest
      password: [email protected]
      roles:
        - VIEW

В этом примере мы собираемся привязать свойство props к List\u003cMap\u003cString, Object\u003e\u003e. Точно так же мы сопоставим пользователей со списком объектов User.

Поскольку каждый элемент записи реквизита содержит разные ключи, мы можем внедрить его как список карт. Обязательно ознакомьтесь с нашей статьей о том, как внедрить карту из файла YAML в Spring Boot.

Однако в случае с пользователями все элементы имеют одни и те же ключи, поэтому для упрощения их сопоставления нам может потребоваться создать специальный класс User для инкапсуляции ключей в виде полей:

public class ApplicationProps {
    
    // ...
	
    private List<Map<String, Object>> props;
    private List<User> users;
    
    // getters and setters

    public static class User {

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

        // getters and setters

    }
}

Теперь мы убедимся, что наши вложенные списки 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("[email protected]@");
        assertThat(applicationProps.getProps().get(0).get("name")).isEqualTo("YamlList");
        assertThat(applicationProps.getProps().get(1).get("port").getClass()).isEqualTo(Integer.class);
    }
	
}

5. Заключение

В этом руководстве мы узнали, как отображать списки YAML в списки Java. Мы также проверили, как привязать сложные списки к пользовательским объектам POJO.


Как всегда, полный исходный код этой статьи доступен на GitHub.