Чтение и запись файлов YAML на Java с помощью SnakeYAML

Введение YAML [https://yaml.org/] означает YAML Ain't Markup Language, это язык сериализации данных, наиболее часто используемый для указания деталей конфигурации проекта. Основная мотивация YAML заключается в том, что он разработан в удобном для человека формате. С первого взгляда мы можем получить представление о свойствах и их соответствующих значениях, а также о взаимосвязи между свойствами, если она существует. Поскольку файлы YAML сейчас используются часто, почти во всех остальных p

Вступление

YAML означает YAML Ain't Markup Language, это язык сериализации данных, наиболее часто используемый для указания деталей конфигурации проекта. Основная мотивация YAML заключается в том, что он разработан в удобном для человека формате. С первого взгляда мы можем получить представление о свойствах и их соответствующих значениях, а также о взаимосвязи между свойствами, если она существует.

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

Для этого мы можем использовать любую из двух популярных библиотек: Jackson или SnakeYAML .

В этой статье мы сосредоточимся на том, как читать и писать файлы YAML на Java с помощью SnakeYAML .

ЗмеяYAML

SnakeYAML - это библиотека анализа YAML с высокоуровневым API для сериализации и десериализации документов YAML.

Точка входа для SnakeYAML является Yaml класс, подобно тому , как ObjectMapper класс является точкой входа в Джексон.

Загрузка документов может выполняться для отдельных документов с помощью load() или в пакетном режиме с помощью loadAll() . Методы принимают InputStream , который является распространенным форматом для поиска файлов, а также String содержащие допустимые данные YAML.

С другой стороны, мы можем dump() Java-объекты в документы YAML - где ключи / поля и значения отображаются в документ.

Естественно, SnakeYAML хорошо работает с Java Maps , учитывая структуру <key>:<value> , однако вы также можете работать с пользовательскими объектами Java.

Если вы используете Maven, установите SnakeYAML, добавив следующую зависимость:

 <dependency> 
 <groupId>org.yaml</groupId> 
 <artifactId>snakeyaml</artifactId> 
 <version>${org.snakeyaml.version}</version> 
 </dependency> 

А если вы используете Gradle , установить SnakeYAML так же просто, как включить в свой файл Gradle следующее:

 compile group: 'org.yaml', name: 'snakeyaml', version: '{version}' 

Вы можете проверить последнюю версию библиотеки в центральном репозитории Maven .

Чтение YAML с помощью SnakeYAML

SnakeYAML позволяет вам читать файл YAML в простой Map или анализировать файл и преобразовывать его в пользовательский объект Java. В зависимости от ваших требований вы можете решить, в каком формате вы хотите читать свои файлы YAML. Давайте посмотрим на оба подхода.

Чтение файла YAML как карты на Java

Начнем с чтения простого файла YAML как набора пар ключ-значение. Файл, который мы будем читать, будет содержать следующие данные:

 id: 20 
 name: Bruce 
 year: 2020 
 address: Gotham City 
 department: Computer Science 

Предположим, у нас есть этот YAML в папке ресурсов нашего Java-проекта. Давайте сначала загрузим файл как InputStream

Затем мы Yaml экземпляр Yaml, который является точкой входа в использование библиотеки. Yaml знакомит нас с такими методами, как load() которые позволяют нам читать и анализировать любой InputStream , Reader или String с действительными данными YAML:

 InputStream inputStream = new FileInputStream(new File("student.yml")); 
 
 Yaml yaml = new Yaml(); 
 Map<String, Object> data = yaml.load(inputStream); 
 System.out.println(data); 

Метод возвращает Map Java, в которой имена свойств используются в качестве ключей к их соответствующим значениям.

Обратите внимание, что значения на Map имеют тип Object , потому что в файле YAML мы можем иметь наши данные в виде строковых значений, чисел или даже коллекций. Все это может быть помещено в Object поэтому он включает в себя любое значение, которое мы можем ввести.

Если мы напечатаем наш data в который мы загрузили файл YAML, мы получим следующий результат:

 {id=20, name=Bruce, year=2020, address=Gotham City, department=Computer Science} 

Как видите, свойства из файла YAML просто отображаются как пары ключ-значение в объекте Java Map.

Давайте обновим наш YAML-файл, чтобы он также содержал данные коллекции. YAML-файл обновления выглядит так:

 id: 20 
 name: Bruce 
 year: 2020 
 address: Gotham City 
 department: Computer Science 
 courses: 
 - name: Algorithms 
 credits: 6 
 - name: Data Structures 
 credits: 5 
 - name: Design Patterns 
 credits: 3 

Теперь наш файл YAML содержит коллекцию courses с несколькими значениями данных.

Чтобы прочитать обновленный файл YAML, нет необходимости обновлять наш код Java. Наш предыдущий код сможет успешно загрузить файл YAML в наш объект Map После прочтения файла результат будет:

 { 
 id=20, name=Bruce, year=2020, address=Gotham City, department=Computer Science, 
 courses=[{name=Algorithms, credits=6}, {name=Data Structures, credits=5}, {name=Design Patterns, credits=3}] 
 } 

Элемент курсов в файле YAML читается как ArrayList где каждое значение в списке является самим объектом Map

Чтение объекта YAML как настраиваемого объекта Java

Теперь, когда мы успешно использовали YAML-файл в нашем Java-коде в виде простых пар ключ-значение, давайте загрузим тот же файл, что и пользовательский Java-объект, что является гораздо более распространенным вариантом использования.

Мы будем использовать следующие классы Java для загрузки данных из наших файлов YAML:

 public class Person { 
 private long id; 
 private String name; 
 private String address; 
 // Getters and setters 
 } 
 
 public class Student extends Person { 
 private int year; 
 private String department; 
 private List<Course> courses; 
 // Getters and setters 
 } 
 
 public class Course { 
 private String name; 
 private double credits; 
 // Getters and setters 
 } 

Мы загрузим данные в Student , где элемент курсов из файла YAML будет преобразован в List типа Course .

Мы будем использовать тот же файл YAML, который мы использовали в предыдущем примере, и загрузим его как InputStream :

 InputStream inputStream = new FileInputStream(new File("student_with_courses.yml")); 
 Yaml yaml = new Yaml(new Constructor(Student.class)); 
 Student data = yaml.load(inputStream); 
 System.out.println(data); 

Теперь, когда мы создаем наш Yaml , мы указываем тип данных, в который мы хотим преобразовать данные. new Constructor(Student.class) сообщает SnakeYAML читать данные из файла YAML, сопоставляя их с нашим объектом Student

Сопоставление простое, и имена атрибутов вашего объекта должны совпадать с именами атрибутов YAML ( courses -> courses ).

Это приводит к:

 Student[Person[id=20, name='Bruce', address='Gotham City'], year=2020, department='Computer Science', courses=[Course[name='Algorithms', credits=6.0], Course[name='Data Structure', credits=5.0], Course[name='Design patters', credits=3.0]]] 

Как вы можете видеть, SnakeYAML успешно создал Student , сохранив при этом Student (родительский класс Person ) и связь с классом Course

Написание YAML с помощью SnakeYAML

Теперь, когда мы успешно прочитали файлы YAML в нашем коде Java, давайте приступим к записи данных в файлы YAML с помощью нашего проекта Java. Подобно чтению документов YAML, мы можем записать простую Map Java и пользовательский объект Java в файл YAML.

Записать карту в YAML

Давайте сначала напишем простой Map в файл YAML:

 Map<String, Object> dataMap = new HashMap<>(); 
 dataMap.put("id", 19); 
 dataMap.put("name", "John"); 
 dataMap.put("address", "Star City"); 
 dataMap.put("department", "Medical"); 

Теперь давайте создадим новый PrintWriter с учетом выходного каталога и dump() dataMap используя этот писатель.

Примечание. Метод dump() принимает любой Writer :

 PrintWriter writer = new PrintWriter(new File("./src/main/resources/student_output.yml")); 
 Yaml yaml = new Yaml(); 
 yaml.dump(dataMap, writer); 

В результате получается файл, содержащий:

 {address: Star City, name: John, id: 19, department: Medical} 

Примечание: выходной файл YAML не имеет значений в той же последовательности, в которой мы добавляли их в наш Map , поскольку мы использовали HashMap который не сохраняет порядок ввода.

Вы можете решить эту проблему, используя вместо этого LinkedHashMap

Записать пользовательский объект Java в YAML

Теперь давайте попробуем сохранить наш Student в формате YAML в выходном файле. Для этого мы будем использовать следующий код для настройки объекта Student

 Student student = new Student(); 
 
 student.setId(21); 
 student.setName("Tim"); 
 student.setAddress("Night City"); 
 student.setYear(2077); 
 student.setDepartment("Cyberware"); 
 
 Course courseOne = new Course(); 
 courseOne.setName("Intelligence"); 
 courseOne.setCredits(5); 
 
 Course courseTwo = new Course(); 
 courseTwo.setName("Crafting"); 
 courseTwo.setCredits(2); 
 
 List<Course> courseList = new ArrayList<>(); 
 courseList.add(courseOne); 
 courseList.add(courseTwo); 
 
 student.setCourses(courseList); 

Теперь давайте используем наш экземпляр Yaml с реализацией Writer dump() данных в файл:

 PrintWriter writer = new PrintWriter(new File("./src/main/resources/student_output_bean.yml")); 
 Yaml yaml = new Yaml(); 
 yaml.dump(student, writer); 

Это приводит к:

 !!model.Student 
 address: Night City 
 courses: 
 - {credits: 5.0, name: Intelligence} 
 - {credits: 2.0, name: Crafting} 
 department: Cyberware 
 id: 21 
 name: Tim 
 year: 2077 

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

Хотя оба сгенерированных выходных файла имеют допустимый синтаксис YAML, если вы хотите создать файл YAML в более часто используемом формате, где каждое значение записывается в одной строке и нет скобок, вы можете настроить DumperOptions и передать его в конструктор Yaml

 DumperOptions options = new DumperOptions(); 
 options.setIndent(2); 
 options.setPrettyFlow(true); 
 options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); 
 Yaml yaml = new Yaml(options); 

Здесь мы указали отступ и поток документов YAML с DumperOptions объекта DumperOptions. Теперь, когда мы используем функцию dump Yaml мы получим вывод в другом формате:

 !!model.Student 
 address: Night City 
 courses: 
 - credits: 5.0 
 name: Intelligence 
 - credits: 2.0 
 name: Crafting 
 department: Cyberware 
 id: 21 
 name: Tim 
 year: 2077 

Заключение

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

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

Исходный код примера кода можно найти на GitHub .

comments powered by Disqus