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}
Полностью идентичен значениям, которые мы настроили!