YAML — это широко известный в сообществе Ruby формат , довольно широко используемый уже давно. Но мы, как разработчики Java, в основном имеем дело с файлами свойств и XML-файлами на случай, если нам понадобится некоторая конфигурация для наших приложений. Сколько раз нам нужно было выразить сложную конфигурацию, изобретая нашу собственную XML-схему или навязывая соглашение об именах свойств?
Хотя JSON становится популярным форматом для веб-приложений, использование файлов JSON для описания конфигурации немного громоздко и, на мой взгляд, не так выразительно, как YAML . Давайте посмотрим, что YAML может сделать для нас, чтобы сделать нашу жизнь проще.
Обязательно начнем с проблемы. Для того чтобы наше приложение функционировало правильно, нам нужно как-то передать ему следующие данные:
- версия и дата выпуска
- параметры подключения к базе данных
- список поддерживаемых протоколов
- список пользователей с их паролями
Этот список параметров звучит немного странно, но цель состоит в том, чтобы продемонстрировать различные типы данных в работе: строки, числа, даты, списки и карты. Модель Java состоит из двух простых классов: Connection
package com.example.yaml; public final class Connection { private String url; private int poolSize; public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public int getPoolSize() { return poolSize; } public void setPoolSize(int poolSize) { this.poolSize = poolSize; } @Override public String toString() { return String.format( "'%s' with pool of %d", getUrl(), getPoolSize() ); } }
и Конфигурация , оба являются типичными Java POJO, подробными из-за установщиков и получателей свойств (мы к этому привыкли, верно?).
package com.example.yaml; import static java.lang.String.format; import java.util.Date; import java.util.List; import java.util.Map; public final class Configuration { private Date released; private String version; private Connection connection; private List< String > protocols; private Map< String, String > users; public Date getReleased() { return released; } public String getVersion() { return version; } public void setReleased(Date released) { this.released = released; } public void setVersion(String version) { this.version = version; } public Connection getConnection() { return connection; } public void setConnection(Connection connection) { this.connection = connection; } public List< String > getProtocols() { return protocols; } public void setProtocols(List< String > protocols) { this.protocols = protocols; } public Map< String, String > getUsers() { return users; } public void setUsers(Map< String, String > users) { this.users = users; } @Override public String toString() { return new StringBuilder() .append( format( "Version: %s\n", version ) ) .append( format( "Released: %s\n", released ) ) .append( format( "Connecting to database: %s\n", connection ) ) .append( format( "Supported protocols: %s\n", protocols ) ) .append( format( "Users: %s\n", users ) ) .toString(); } }
Так как модель достаточно ясна, давайте попробуем выразить это так, как это обычно делает человек. Возвращаясь к нашему списку необходимых настроек, давайте попробуем записать их по очереди. 1. версия и дата выпуска
version: 1.0 released: 2012-11-30
2. параметры подключения к базе данных
connection: url: jdbc:mysql://localhost:3306/db poolSize: 5
3. список поддерживаемых протоколов
protocols: - http - https
4. список пользователей с их паролями
users: tom: passwd bob: passwd
И на этом наша конфигурация, выраженная в синтаксисе YAML, завершена! Весь файл sample.yml выглядит так:
version: 1.0 released: 2012-11-30 # Connection parameters connection: url: jdbc:mysql://localhost:3306/db poolSize: 5 # Protocols protocols: - http - https # Users users: tom: passwd bob: passwd
Чтобы заставить его работать в Java, нам просто нужно использовать потрясающую библиотеку snakeyml , соответственно файл POM Maven довольно прост:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelversion>4.0.0</modelversion> <groupid>com.example</groupid> <artifactid>yaml</artifactid> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <properties> <project.build.sourceencoding>UTF-8</project.build.sourceencoding> </properties> <dependencies> <dependency> <groupid>org.yaml</groupid> <artifactid>snakeyaml</artifactid> <version>1.11</version> </dependency> </dependencies> <build> <plugins> <groupid>org.apache.maven.plugins</groupid> <artifactid>maven-compiler-plugin</artifactid> <version>2.3.1</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugins> </build> </project>
Обратите внимание на использование Java 1.7 , языковые расширения и дополнительные библиотеки упрощают многие обычные задачи, как мы могли видеть, рассматривая YamlConfigRunner :
package com.example.yaml; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Paths; import org.yaml.snakeyaml.Yaml; public class YamlConfigRunner { public static void main(String[] args) throws IOException { if( args.length != 1 ) { System.out.println( "Usage: <file.yml>" ); return; } Yaml yaml = new Yaml(); try( InputStream in = Files.newInputStream( Paths.get( args[ 0 ] ) ) ) { Configuration config = yaml.loadAs( in, Configuration.class ); System.out.println( config.toString() ); } } }
Фрагмент кода здесь загружает конфигурацию из файла ( args [0] ), пытается проанализировать ее и заполнить класс Configuration значимыми данными, используя соглашения JavaBeans , преобразуя, где это возможно, в объявленные типы. Выполнение этого класса с sample.yml в качестве аргумента приводит к следующему выводу:
Version: 1.0 Released: Thu Nov 29 19:00:00 EST 2012 Connecting to database: 'jdbc:mysql://localhost:3306/db' with pool of 5 Supported protocols: [http, https] Users: {tom=passwd, bob=passwd}
Полностью идентичен значениям, которые мы настроили!