DevOps系列文章 之 SnakeYAML解析与序列化YAML

1、简述

如何使用SnakeYAML库将
YAML文档转换为Java对象,以及JAVA对象如何序列化为YAML文档

在DevOps平台系统中是基础的能力支持,不管是spring boot 的配置还是K8S 资源清单yaml

2、项目设置

要在项目中使用SnakeYAML,需要添加Maven依赖项(可在此处找到最新版本)

<dependency><groupId>org.yaml</groupId><artifactId>snakeyaml</artifactId><version>1.25</version>
</dependency>

3、入口点

YAML类是API的入口点:

Yaml yaml = new Yaml()

由于实现不是线程安全的,因此不同的线程必须具有自己的Yaml实例。

4、加载YAML文档

SnakeYAML支持从StringInputStream加载文档,我们从定义一个简单的YAML文档开始,然后将文件命名为customer.yaml

基本用法

现在,我们将使用Yaml类来解析上述YAML文档:

public class YamlTest {public static void main(String[] args) {Yaml yaml = new Yaml();InputStream inputStream = YamlTest.class.getClassLoader().getResourceAsStream("customer.yaml");Map<String, Object> obj = yaml.load(inputStream);System.out.println(obj);}
}

上面的代码生成以下输出: 

 

默认情况下,load()方法返回一个Map对象。查询Map对象时,我们需要事先知道属性键的名称,否则容易出错。更好的办法是自定义类型。

自定义类型解析

SnakeYAML提供了一种将文档解析为自定义类型的方法

让我们定义一个Customer类,然后尝试再次加载该文档:

package com.devops.autocicdstore.yaml;/*** @Author 虎哥* @Description //TODO* |要带着问题去学习,多猜想多验证|**/public class Customer {private String firstName;private String lastName;private int age;// getters and setterspublic String getFirstName() {return firstName;}public void setFirstName(String firstName) {this.firstName = firstName;}public String getLastName() {return lastName;}public void setLastName(String lastName) {this.lastName = lastName;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Customer{" +"firstName='" + firstName + '\'' +", lastName='" + lastName + '\'' +", age=" + age +'}';}
}

现在我么来加载: 

        Yaml yaml = new Yaml(new Constructor(Customer.class));InputStream inputStream = YamlTest.class.getClassLoader().getResourceAsStream("customer.yaml");Customer customer = yaml.load(inputStream);System.out.println(customer);

隐式类型

如果没有为给定属性定义类型,则库会自动将值转换为隐式type

例如:

1.0 -> Float
42 -> Integer
2009-03-30 -> Date

让我们使用一个TestCase来测试这种隐式类型转换:

@org.junit.Testpublic void whenLoadYAML_thenLoadCorrectImplicitTypes() {Yaml yaml = new Yaml();Map<Object, Object> document = yaml.load("3.0: 2018-07-22");System.out.println(document);assertNotNull(document);assertEquals(1, document.size());assertTrue(document.containsKey(3.0d));}

嵌套对象

SnakeYAML 支持嵌套的复杂类型。

让我们向“ customer.yaml”添加“ 联系方式”  和“ 地址” 详细信息并将新文件另存为customer_with_contact_details_and_address.yaml.

现在,我们将分析新的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类:

package com.devops.autocicdstore.yaml;import java.util.List;/*** @Author 虎哥* @Description //TODO* |要带着问题去学习,多猜想多验证|**/public class Customer {private String firstName;private String lastName;private int age;private List<Contact> contactDetails;private Address homeAddress;public String getFirstName() {return firstName;}public void setFirstName(String firstName) {this.firstName = firstName;}public String getLastName() {return lastName;}public void setLastName(String lastName) {this.lastName = lastName;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public List<Contact> getContactDetails() {return contactDetails;}public void setContactDetails(List<Contact> contactDetails) {this.contactDetails = contactDetails;}public Address getHomeAddress() {return homeAddress;}public void setHomeAddress(Address homeAddress) {this.homeAddress = homeAddress;}@Overridepublic String toString() {return "Customer{" +"firstName='" + firstName + '\'' +", lastName='" + lastName + '\'' +", age=" + age +", contactDetails=" + contactDetails +", homeAddress=" + homeAddress +'}';}
}
package com.devops.autocicdstore.yaml;/*** @Author 虎哥* @Description //TODO* |要带着问题去学习,多猜想多验证|**/
public class Address {private String line;private String city;private String state;private Integer zip;public String getLine() {return line;}public void setLine(String line) {this.line = line;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}public String getState() {return state;}public void setState(String state) {this.state = state;}public Integer getZip() {return zip;}public void setZip(Integer zip) {this.zip = zip;}@Overridepublic String toString() {return "Address{" +"line='" + line + '\'' +", city='" + city + '\'' +", state='" + state + '\'' +", zip=" + zip +'}';}
}
package com.devops.autocicdstore.yaml;/*** @Author 虎哥* @Description //TODO* |要带着问题去学习,多猜想多验证|**/
public class Contact {private String type;private int number;public String getType() {return type;}public void setType(String type) {this.type = type;}public int getNumber() {return number;}public void setNumber(int number) {this.number = number;}@Overridepublic String toString() {return "Contact{" +"type='" + type + '\'' +", number=" + number +'}';}
}

现在,我们来测试下Yamlload()

@Testpublic voidwhenLoadYAMLDocumentWithTopLevelClass_thenLoadCorrectJavaObjectWithNestedObjects() {Yaml yaml = new Yaml(new Constructor(Customer.class));InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("customer_with_contact_details_and_address.yaml");Customer customer = yaml.load(inputStream);System.out.println(customer);assertNotNull(customer);assertEquals("John", customer.getFirstName());assertEquals("Doe", customer.getLastName());assertEquals(31, customer.getAge());assertNotNull(customer.getContactDetails());assertEquals(2, customer.getContactDetails().size());assertEquals("mobile", customer.getContactDetails().get(0).getType());assertEquals(123456789, customer.getContactDetails().get(0).getNumber());assertEquals("landline", customer.getContactDetails().get(1).getType());assertEquals(456786868, customer.getContactDetails().get(1).getNumber());assertNotNull(customer.getHomeAddress());assertEquals("Xyz, DEF Street", customer.getHomeAddress().getLine());}

 

类型安全的集合

当给定Java类的一个或多个属性是泛型集合类时,需要通过TypeDescription来指定泛型类型,以便可以正确解析。

让我们假设 一个Customer拥有多个Contact

firstName: "John"
lastName: "Doe"
age: 31
contactDetails:- { type: "mobile", number: 123456789}- { type: "landline", number: 123456789}

为了能正确解析,我们可以在顶级类上为给定属性指定TypeDescription 

@Testpublic void test1(){Constructor constructor = new Constructor(Customer.class);TypeDescription customTypeDescription = new TypeDescription(Customer.class);customTypeDescription.addPropertyParameters("contactDetails", Contact.class);constructor.addTypeDescription(customTypeDescription);Yaml yaml = new Yaml(new Constructor(Customer.class));InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("customer_with_contact_details_and_address.yaml");Customer customer = yaml.load(inputStream);System.out.println(customer);}

 

 

载入多个文件

在某些情况下,单个文件中可能有多个YAML文档,而我们想解析所有文档。所述YAML类提供了一个LOADALL()方法来完成这种类型的解析。

假设下面的内容在一个文件中:

---
firstName: "John"
lastName: "Doe"
age: 20
---
firstName: "Jack"
lastName: "Jones"
age: 25

我们可以使用loadAll()方法解析以上内容,如以下代码示例所示:

@Testpublic void whenLoadMultipleYAMLDocuments_thenLoadCorrectJavaObjects() {Yaml yaml = new Yaml(new Constructor(Customer.class));InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("customers.yaml");int count = 0;for (Object object : yaml.loadAll(inputStream)) {count++;assertTrue(object instanceof Customer);System.out.println(object);}assertEquals(2,count);}

5、生成YAML文件

SnakeYAML 支持 将java对象序列化为yml。

基本用法

我们将从一个将Map <String,Object>的实例转储到YAML文档(String)的简单示例开始:

@Testpublic void whenDumpMap_thenGenerateCorrectYAML() {Map<String, Object> data = new LinkedHashMap<String, Object>();data.put("name", "Silenthand Olleander");data.put("race", "Human");data.put("traits", new String[] { "ONE_HAND", "ONE_EYE" });Yaml yaml = new Yaml();StringWriter writer = new StringWriter();yaml.dump(data, writer);String expectedYaml = "name: Silenthand Olleander\nrace: Human\ntraits: [ONE_HAND, ONE_EYE]\n";System.out.println(writer);assertEquals(expectedYaml, writer.toString());}

上面的代码产生以下输出(请注意,使用LinkedHashMap的实例将保留输出数据的顺序):

自定义Java对象

我们还可以选择将自定义Java类型转储到输出流中

 @Testpublic void whenDumpACustomType_thenGenerateCorrectYAML() {Customer customer = new Customer();customer.setAge(45);customer.setFirstName("Greg");customer.setLastName("McDowell");Yaml yaml = new Yaml();StringWriter writer = new StringWriter();yaml.dump(customer, writer);String expectedYaml = "!!com.devops.autocicdstore.yaml.Customer {age: 45, contactDetails: null, firstName: Greg,\n  homeAddress: null, lastName: McDowell}\n";System.out.println(writer);assertEquals(expectedYaml, writer.toString());}

 

 

生成内容会包含!!com.devops.autocicdstore.yaml.Customer,为了避免在输出文件中使用标签名,我们可以使用库提供的  dumpAs()方法。

因此,在上面的代码中,我们可以进行以下调整以删除标记:

yaml.dumpAs(customer, Tag.MAP, null);
String ccustomerStr = yaml.dumpAs(customer, Tag.MAP, null);
System.out.println(ccustomerStr);

 

 本文说明了SnakeYAML库解析和序列化YAML文档。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/14447.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

百度网盘删除“我的应用数据”文件夹

方法一&#xff1a;电脑端 工具链接&#xff0c; BaiduPCS-Go-3.6.8-windows-86.zip - 蓝奏云 电脑端下载解压运行&#xff0c;弹出浏览器窗口和命令行&#xff0c;在浏览器中输入百度网盘账号密码&#xff0c;登录。 之后会需要输入验证码&#xff0c;之后使用手机号或者邮…

恒生电子探路金融大模型

‍数据智能产业创新服务媒体 ——聚焦数智 改变商业 近日&#xff0c;恒生电子和旗下子公司恒生聚源正式发布基于大语言模型技术打造的数智金融新品&#xff1a;金融智能助手光子和全新升级的智能投研平台WarrenQ。此外&#xff0c;恒生电子金融行业大模型LightGPT也首次对外亮…

Ctfshow web入门 nodejs篇 web334-web344

CTFshow NodeJs web334 前言&#xff1a;做原型链污染&#xff0c;入门的话个人建议先看看P神的文章&#xff0c;只看前四部分就行了。 深入理解 JavaScript Prototype 污染攻击 | 离别歌 (leavesongs.com) 然后也得有一点js基础&#xff0c;不用太多&#xff0c;要不然看起…

web安全php基础_搭建php环境

首先打开phpstudy的网站栏点击创建网站&#xff0c;新建一个网站&#xff08;域名随便输反正是局域网&#xff09;然后点击确认 如下&#xff0c;网站便创建好了 打开浏览器输入刚刚创建网站时输入的域名&#xff0c;即可看见我们的网站 然后网站好了&#xff0c;就可以新建项…

Vue和React的区别?

目录 共同点 1. 数据驱动视图 2. 组件化 3. Virtual DOM 不同点 1. 核心思想不同 2. 组件写法差异 3. diff算法不同 4. 响应式原理不同 5. 其他不同点 首先找到 Vue 和 React 的共性&#xff0c;它们被用于解决什么问题&#xff0c; 然后再挖掘各自独特的个性、设计原…

基于WebSocket的简易聊天室的基本实现梳理

一&#xff0c;前言 目前在很多网站为了实现推送技术所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔&#xff08;如每1秒&#xff09;&#xff0c;由浏览器对服务器发出HTTP请求&#xff0c;然后由服务器返回最新的数据给客户端的浏览器。HTTP 协议是一种无状态的、无连…

【Rust】所有权

文章目录 所有权stack与heap所有权存在的原因所有权规则变量作用域String类型内存和分配变量与数据交互的方式1.Move2.Clone3.Copy 所有权与函数返回值与作用域引用借用可变引用悬空引用Dangling References引用的规则切片字符串切片将字符串切片作为参数传递其他类型的切片 所…

CentOS Linux的替代品(六)_BigCloud Enterprise Linux R8 U2 基础安装教程

文章目录 CentOS Linux的替代品&#xff08;六&#xff09;_BigCloud Enterprise Linux R8 U2 基础安装教程一、BC-Linux简介二、BigCloud Enterprise Linux R8 U2 基础安装2.1 下载地址2.2 安装过程 三、简单使用3.1 关闭selinux3.1.1 临时关闭selinux3.1.2 永久关闭selinux 3…

SpringBoot中间件——封装限流器

背景 通常能知道一个系统服务在正产增速下流量大小&#xff0c;扩容与压测也是基于此。若有突发或者恶意攻击访问&#xff0c;都要将流量拦截在外。这部分功能不属于业务侧&#xff0c;它是通用非业务的共性需求&#xff0c;所以我们将共性抽取为限流中间件。 方案设计 图解&…

多元回归预测 | Matlab鲸鱼算法(WOA)优化极限梯度提升树XGBoost回归预测,WOA-XGBoost回归预测模型,多变量输入模型

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 多元回归预测 | Matlab鲸鱼算法(WOA)优化极限梯度提升树XGBoost回归预测,WOA-XGBoost回归预测模型,多变量输入模型 评价指标包括:MAE、RMSE和R2等,代码质量极高,方便学习和替换数据。要求2018版本及以上。 部分源…

LeViT-UNet:transformer 编码器和CNN解码器的有效整合

levi - unet[2]是一种新的医学图像分割架构&#xff0c;它使用transformer 作为编码器&#xff0c;这使得它能够更有效地学习远程依赖关系。levi - unet[2]比传统的U-Nets更快&#xff0c;同时仍然实现了最先进的分割性能。 levi - unet[2]在几个具有挑战性的医学图像分割基准…

【Python】Python基础知识总结

&#x1f389;欢迎来到Python专栏~Python基础知识总结 ☆* o(≧▽≦)o *☆嗨~我是小夏与酒&#x1f379; ✨博客主页&#xff1a;小夏与酒的博客 &#x1f388;该系列文章专栏&#xff1a;Python学习专栏 文章作者技术和水平有限&#xff0c;如果文中出现错误&#xff0c;希望…