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”的内容,你了解清楚吗?希望对你有所帮助,任何问题可以给我留言,让我们下期再见吧。