JAVA基于SnakeYAML实现解析与序列化YAML

概述
本文将详细介绍如何使用SnakeYAML库在Java中进行YAML文档的解析和序列化,我们将从项目设置开始,逐步讲解如何加载、解析、自定义类型、处理隐式类型以及嵌套对象等。
项目设置
要在项目中使用SnakeYAML,需要添加Maven依赖项(可在此处找到最新版本):
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.25</version>
</dependency>
入口点
该YAML类是API的入口点:
Yaml yaml = new Yaml();
由于实现不是线程安全的,因此不同的线程必须具有自己的Yaml实例。
加载YAML文档
SnakeYAML支持从String或InputStream加载文档,我们从定义一个简单的YAML文档开始,然后将文件命名为customer.yaml:
firstName: "John" lastName: "Doe" age: 20
4.1 基本用法
我们将使用Yaml类来解析上述YAML文档:
Yaml yaml = new Yaml();
InputStream inputStream = this.getClass()
.getClassLoader()
.getResourceAsStream("customer.yaml");
Map<String, Object> obj = yaml.load(inputStream);
System.out.println(obj);
上面的代码生成以下输出:
{firstName=John, lastName=Doe, age=20}
默认情况下,load()方法返回一个Map对象,查询Map对象时,我们需要事先知道属性键的名称,否则容易出错,更好的办法是自定义类型。
4.2 自定义类型解析

SnakeYAML提供了一种将文档解析为自定义类型的方法,让我们定义一个Customer类,然后尝试再次加载该文档:
public class Customer {
private String firstName;
private String lastName;
private int age;
// getters and setters
}
现在我么来加载:
Yaml yaml = new Yaml();
InputStream inputStream = this.getClass()
.getClassLoader()
.getResourceAsStream("customer.yaml");
Customer customer = yaml.load(inputStream);
还有一种方法是使用Constructor:
Yaml yaml = new Yaml(new Constructor(Customer.class));
4.3 隐式类型
如果没有为给定属性定义类型,则库会自动将值转换为隐式type。
1.0 >Float
42 >Integer
20090330 >Date
让我们使用一个TestCase来测试这种隐式类型转换:
@Test
public void whenLoadYAML_thenLoadCorrectImplicitTypes() {
Yaml yaml = new Yaml();
Map<Object, Object> document = yaml.load("3.0: 20180722");
assertNotNull(document);
assertEquals(1, document.size());
assertTrue(document.containsKey(3.0d));
}
4.4 嵌套对象

SnakeYAML 支持嵌套的复杂类型,让我们向“ customer.yaml”添加“联系方式”和“地址”详细信息,并将新文件另存为customer_with_contact_details_and_address.yaml:
firstName: "John"
lastName: "Doe"
age: 31
contactDetails:
type: "mobile"
number: 123456789
type: "landline"
number: 456786868
homeAddress:
line: "Xyz, DEF Street"
city: "City Y"
state: "State Y"
zip: 345657
我们来更新java类:
public class Customer {
private String firstName;
private String lastName;
private int age;
private List<Contact> contactDetails;
private Address homeAddress;
// getters and setters
}
public class Contact {
private String type;
private int number;
// getters and setters
}
public class Address {
private String line;
private String city;
private String state;
private Integer zip;
// getters and setters
}
我们来测试下Yaml的load():
@Test
public void whenLoadYAMLDocumentWithTopLevelClass_thenLoadCorrectJavaObjectWithNestedObjects() {
Yaml yaml = new Yaml(new Constructor(Customer.class));
InputStream inputStream = this.getClass()
.getClassLoader()
.getResourceAsStream("yaml/customer_with_contact_details_and_address.yaml");
Customer customer = yaml.load(inputStream);
assertNotNull(customer);
assertEquals("John", customer.getFirstName());
}
相关问题与解答栏目
问题1: SnakeYAML如何处理线程安全问题?
答案: SnakeYAML的实现不是线程安全的,因此每个线程应创建自己的Yaml实例,这可以通过在需要的地方创建局部变量来实现。
问题2: 如果YAML文件中的属性没有明确指定类型,SnakeYAML会如何处理?
答案: 如果YAML文件中的属性没有明确指定类型,SnakeYAML会根据内容自动推断类型,字符串会被解析为String,整数会被解析为Integer,浮点数会被解析为Float等。
小伙伴们,上文介绍了“JAVA基于SnakeYAML实现解析与序列化YAML”的内容,你了解清楚吗?希望对你有所帮助,任何问题可以给我留言,让我们下期再见吧。














