Loading Configuration File Using YAML

0

YAML is a recursive acronym for “YAML Ain’t Markup Language”.

YAML is a readable text format for data structures. YAML can handle many common data types and structures. Some of the characteristics are:

  1. It uses Unicode printable characters.
  2. Some of the characters are used to provide structural information. For example, colons separate key: value pairs, and dashes are used to create lists.
  3. YAML minimizing the amount of structural characters and allowing the data to show itself in a natural and meaningful way. For example, indentation is used for structure.

YAML can be used to load configuration files. Instead of creating a custom schema and XML, YAML provides an easy way of mapping the data provided to POJOs.

In this example, we will use snakeyaml as YAML parser.

Dependencies

Our example depends on:

  1. snakeyaml – YAML parser for java
  2. guava – Guava for some utility methods

pom.xml:

<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.javarticles.yaml</groupId>
	<artifactId>yamlExample</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<dependencies>
		<dependency>
			<groupId>org.yaml</groupId>
			<artifactId>snakeyaml</artifactId>
			<version>1.16</version>
		</dependency>
		<dependency>
			<groupId>com.google.guava</groupId>
			<artifactId>guava</artifactId>
			<version>18.0</version>
		</dependency>

	</dependencies>

</project>

YAML format

Mapping key and value

You can add a key value pair with a colon separating the key from its value.

hostName: 134.37.74.171
port: 8080

List

You can specify a list in YAML by placing each member of the list on a new line with an opening dash. These lists are called sequences.

    - name: cmp1
      logDir: C:\\cmp1\\logs
      logFile: cmp1.log

    - name: cmp2
      logDir: C:\\cmp2\\logs
      logFile: cmp2.log

Nested List

You can include a sequence within another sequence by giving the sequence an empty dash, followed by an indented list.

componentProperties:
 -
  - no_of_repeats: 4
  - batch_size: 100
 -
  - no_of_repeats: 3
  - batch_size: 200          

Here is the complete YAML configuration file.

config.yaml:

hostName: 134.37.74.171
port: 8080
components: 
    - name: cmp1
      logDir: C:\\cmp1\\logs
      logFile: cmp1.log
      componentProperties:
          no_of_repeats: 4
          batch_size: 100
    - name: cmp2
      logDir: C:\\cmp2\\logs
      logFile: cmp2.log
      componentProperties:
          no_of_repeats: 3
          batch_size: 200
componentProperties:
 -
  - no_of_repeats: 4
  - batch_size: 100
 -
  - no_of_repeats: 3
  - batch_size: 200          

We will map the YAML configuration data to the below POJOs.

Service:

package com.javarticles.yaml;

import java.util.List;

import com.google.common.base.MoreObjects;

public class Service {
    private String hostName;
    private String port;
    private List components;
    private List<List> componentProperties;

    public String getHostName() {
        return hostName;
    }

    public void setHostName(String hostName) {
        this.hostName = hostName;
    }

    public String getPort() {
        return port;
    }

    public void setPort(String port) {
        this.port = port;
    }

    public List getComponents() {
        return components;
    }

    public void setComponents(List components) {
        this.components = components;
    }        

    public List<List> getComponentProperties() {
        return componentProperties;
    }

    public void setComponentProperties(List<List> componentProperties) {
        this.componentProperties = componentProperties;
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this).add("hostName", hostName + "\n")
                .add("port", port + "\n")
                .add("Components", components + "\n")
                .add("componentProperties", componentProperties + "\n")
                .toString();
    }
}

Component:

package com.javarticles.yaml;

import java.util.Map;

import com.google.common.base.MoreObjects;

public class Component {
    private String name;
    private String logDir;
    private String logFile;
    private Map<String, String> componentProperties;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getLogDir() {
        return logDir;
    }

    public void setLogDir(String logDir) {
        this.logDir = logDir;
    }

    public String getLogFile() {
        return logFile;
    }

    public void setLogFile(String logFile) {
        this.logFile = logFile;
    }

    public Map<String, String> getComponentProperties() {
        return componentProperties;
    }

    public void setComponentProperties(Map<String, String> componentProperties) {
        this.componentProperties = componentProperties;
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this).add("name", name + "\n")
                .add("logDir", logDir + "\n").add("logFile", logFile + "\n")
                .add("componentProperties", componentProperties + "\n")
                .toString();
    }
}

Create instance if Yaml and call loadAs(). Pass in the YAML content in form of byte array and the POJO class to be mapped to.

Service service = new Yaml().loadAs(
                new ByteArrayInputStream(ByteStreams.toByteArray(is))
                , Service.class)

YamlLoadExample:

package com.javarticles.yaml;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

import org.yaml.snakeyaml.Yaml;

import com.google.common.io.ByteStreams;

public class YamlLoadExample {
    
    public static void main(String[] args) throws IOException {
        YamlLoadExample loader = new YamlLoadExample();
        Service service = loader.loadConfig();
        System.out.println(service);
    }
    
    public Service loadConfig() throws IOException {
        URL url = getConfigURL();
        InputStream is = url.openConnection().getInputStream();
        return new Yaml().loadAs(
                new ByteArrayInputStream(ByteStreams.toByteArray(is))
                , Service.class);
    }

    private URL getConfigURL() throws IOException
    {
        URL url = getClass().getResource("config.yaml");
        url.openStream().close();
        return url;
    }
}

Output:

Service{hostName=134.37.74.171
, port=8080
, Components=[Component{name=cmp1
, logDir=C:\\cmp1\\logs
, logFile=cmp1.log
, componentProperties={no_of_repeats=4, batch_size=100}
}, Component{name=cmp2
, logDir=C:\\cmp2\\logs
, logFile=cmp2.log
, componentProperties={no_of_repeats=3, batch_size=200}
}]
, componentProperties=[[{no_of_repeats=4}, {batch_size=100}], [{no_of_repeats=3}, {batch_size=200}]]
}

Download the source code

This was an example about loading configuration file using YAML.

You can download the source code here: yamlExample.zip
Share.

Comments are closed.