YAML (YAML Ain‘t Markup Language) is a popular data serialization language used for configuration files and data storage. Its main advantages are readability and ease of use compared to other formats like JSON or XML.
In this comprehensive guide, we will explore parsing YAML files in Java using the SnakeYAML library. We will cover:
- What is YAML and why parse it in Java
- Adding SnakeYAML dependency
- Reading a simple YAML file
- Reading nested YAML data structures
- Mapping YAML data to custom Java objects
- Handling syntax errors and exceptions
What is YAML and Why Parse it in Java
YAML is used to store structured data including lists, maps and primitive data types in a format that is friendly for humans to read and write.
Here is an example YAML file:
firstName: John
lastName: Doe
age: 35
address:
line1: 123 Main St
city: Anytown
state: CA
zip: 12345
items:
- apple
- orange
- banana
As you can see, YAML uses basic formatting like spaces, colons and dashes rather than braces and brackets like JSON or tags like XML. This makes YAML ideal for configuration files.
Common uses of YAML include:
- Application configuration files
- Storing data for applications
- As an alternative to JSON or XML
- Kubernetes resource definitions
- Ansible playbooks
In many projects, we need to read data from a YAML file and make it available to a Java application. This is where parsing comes in.
There are a few libraries available for parsing YAML in Java. In this tutorial we will use SnakeYAML which is compact, dependency-free and very easy to use.
Adding the SnakeYAML Dependency
To use SnakeYAML, add the following Maven dependency to your pom.xml
:
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.33</version>
</dependency>
Or if using Gradle:
implementation ‘org.yaml:snakeyaml:1.33‘
This will download SnakeYAML along with its own dependencies.
Reading a Simple YAML File
Let‘s start by parsing a simple YAML file in Java using SnakeYAML:
import org.yaml.snakeyaml.Yaml;
import java.util.Map;
import java.util.LinkedHashMap;
public class Application {
public static void main(String[] args) {
// Load the YAML file data
InputStream inputStream = new FileInputStream("data.yaml");
Yaml yaml = new Yaml();
Map<String,Object> data = yaml.load(inputStream);
// Print the data
System.out.println(data);
}
}
The data.yaml
file contains:
name: John Doe
age: 35
address: 123 Main Street, Anytown
When we run the application, SnakeYAML will parse the YAML content and store it in a Map
with string keys and object values:
{name=John Doe, age=35, address=123 Main Street, Anytown}
We can see the YAML properties mapped neatly as key-value pairs in the Map.
To access a specific property, use:
String name = (String)data.get("name");
Since all values are Object
typed, we have to cast to the correct type like String
or Integer
.
Reading Nested YAML Objects
In addition to simple keys and values, YAML also supports nesting objects and collections like lists and maps.
Here is an example with nested data:
person:
name: John Doe
age: 35
address:
line1: 123 Main St
city: Anytown
state: CA
items:
- apple
- orange
- banana
We can use the same SnakeYAML parsing code as before without any changes to load this nested content.
Accessing the nested address
would look like:
Map<String,Object> address = (Map<String,Object>)data.get("person").get("address");
String city = (String)address.get("city"); // Anytown
And the items
list:
List<String> items = (List<String>)data.get("items");
String item1 = items.get(0); // apple
So SnakeYAML handles nested structures in YAML seamlessly.
Mapping YAML to Custom Java Objects
For complex YAML data models, it is better to parse and map the data to custom domain objects rather than using basic Maps and Lists.
For example, consider this YAML document describing a person:
firstName: John
lastName: Doe
age: 35
address:
line1: 123 Main St
city: Anytown
state: CA
zip: 33333
Let‘s define a Person
class with matching attributes:
public class Person {
private String firstName;
private String lastName;
private int age;
private Address address;
// Constructors, getters and setters
}
public class Address {
private String line1;
private String city;
private String state;
private String zip;
// Constructors, getters and setters
}
Now while parsing, we specify the target Java type and SnakeYAML will automatically map YAML properties to object attributes:
Yaml yaml = new Yaml(new Constructor(Person.class));
InputStream inputStream = new FileInputStream("data.yaml");
Person person = yaml.load(inputStream);
That‘s it! The person
instance contains the parsed data from YAML. We can use normal Java code to access it:
System.out.println(person.getFirstName()); // John
System.out.println(person.getAddress().getState()); // CA
The mapping works if YAML attributes match the names of Java bean properties exactly.
Handling YAML Parsing Errors
When loading invalid YAML content, SnakeYAML will throw exceptions which we need to handle properly:
try {
Yaml yaml = new Yaml();
Map<String,Object> data = yaml.load(inputStream);
} catch(Exception e) {
// Print error
e.printStackTrace();
}
Common errors include:
YamlException
: Error parsing YAML syntaxClassCastException
: Unable to cast YAML values to expected Java types
We should catch these exceptions, print the error details and handle invalid/unexpected data.
For production use cases, log errors and fail gracefully instead of throwing raw exceptions to end users.
Conclusion
In this tutorial, we looked at:
- Why YAML data serialization is useful for application configuration and data storage
- Using SnakeYAML library for parsing YAML files in Java
- Reading YAML as simple key-value maps or custom domain objects
- Accessing nested objects and collections in YAML documents
- Best practices for error handling
SnakeYAML provides an easy way to load YAML data in Java applications. With the power of Java, we can then manipulate the data however we need.
The full code for this tutorial is available on GitHub.