SnakeYaml快速入门

From: https://www.jianshu.com/p/d8136c913e52

在YAML快速入门[https://www.jianshu.com/p/97222440cd08]中,我们已经简单介绍了YAML的语法,本节中主要介绍YAML的配置读取。

目前有很多可以生成和解析YAML的第三方工具,常见的,如SnakeYaml,jYaml,Jackson等,但是不同的工具功能还是差距较大,比如jYaml就不支持合并(<<)和(---)操作。我们下面来看看Springboot使用的SnakeYaml的基本使用方式。

简介

SnakeYaml是一个完整的YAML1.1规范Processor,支持UTF-8/UTF-16,支持Java对象的序列化/反序列化,支持所有YAML定义的类型(map,omap,set,常量,具体参考http://yaml.org/type/index.html)。

快速使用

要使用SnakeYaml,首先引入maven依赖:

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

我们来完成一个最简单的yaml解析例子:

@Test
public void testLoad() {String yamlStr = "key: hello yaml";Yaml yaml = new Yaml();Object ret = yaml.load(yamlStr);System.out.println(ret);
}

结果输出:

{key=hello yaml}

简介解释:
1,使用Yaml类,创建一个Yaml对象,所有的解析操作都是从这个对象开始;
2,声明了一个yaml的字符串(当然也可以使用yaml文档等),定义了一个对象:key: hello yaml;
3,使用Yaml对象的load方法 public Object load(String yaml)加载一段yaml字符串,返回解析之后的对象;
我们通过打印ret的类型:

System.out.println(ret.getClass().getSimpleName());

可以看到,实际创建的是一个Map:LinkedHashMap。

load/loadAll/loadAs 方法使用

Yaml的load方法可以传入多种参数类型:
public Object load(String yaml)
public Object load(InputStream io)
public Object load(Reader io)

三个方法都是通过传入的不同类型的内容,解析得到结果对象。需要注意一点的是,SnakeYaml通过读入的内容是否包含BOM头来判断输入流的编码格式。如果不包含BOM头,默认为UTF-8编码。

下面再来看一个解析案例,这次使用yaml文件的方式。首先创建一个yaml文件:

#test.yaml
- value1
- value2
- value3

很明显结果应该是一个List集合,把该文件放到resources下:

@Test
public void testType() throws Exception {Yaml yaml = new Yaml();List<String> ret = (List<String>)yaml.load(this.getClass().getClassLoader().getResourceAsStream("test.yaml"));System.out.println(ret);
}

打印结果:

[value1, value2, value3]

如果需要加载的yaml文件中包含多个yaml片段,则可以使用loadAll方法加载所有的yaml内容。比如有如下一个yaml文件:

#test2.yaml
sample1: r: 10
sample2:other: haha
sample3:x: 100y: 100

这个yaml文件内容很明显是一个对象(或者map),对象的每一个属性对应的又是一个对象。要加载这个yaml文件,代码应该是:

@Test
public void test2() throws Exception {Yaml yaml = new Yaml();Map<String, Object> ret = (Map<String, Object>) yaml.load(this.getClass().getClassLoader().getResourceAsStream("test2.yaml"));System.out.println(ret);
}

打印结果:

{sample1={r=10}, sample2={other=haha}, sample3={x=100, y=100}}

如果我们稍微修改一下test2.yaml文件:

---
sample1: r: 10
---
sample2:other: haha
--- 
sample3:x: 100y: 100

按照YAML规范,这应该是三个yaml配置片段了。那么如果再使用上面的代码解析,就会报错:

image.png

 

可以看到,load方法无法处理---标记。

这种时候只能使用loadAll方法解析:
public Iterable<Object> loadAll(String yaml)
public Iterable<Object> loadAll(InputStream yaml)
public Iterable<Object> loadAll(Reader yaml)

可以看到,loadAll方法返回的是一个Object的迭代对象,那么其中的每一个Object就是每一个yaml片段解析出来的对象:

@Test
public void test3() throws Exception {Yaml yaml = new Yaml();Iterable<Object> ret = yaml.loadAll(this.getClass().getClassLoader().getResourceAsStream("test2.yaml"));for (Object o : ret) {System.out.println(o);}
}

打印的结果为:

{sample1={r=10}}
{sample2={other=haha}}
{sample3={x=100, y=100}}

可以看到,test2.yaml被解析成了三个Map。
这里需要注意一点的是,SnakeYaml是在每一次遍历的时候(即调用Iteratable的forEach方法的时候),才会去解析下一个---分割的yaml片段。

上面所有的实例,都是把yaml配置转化成Map或者Collection,如果我们想直接把yaml配置转成指定对象呢?下面我们通过三个示例来简单看一下:

#address.yaml
lines: |458 Walkman Dr.Suite #292
city: Royal Oak
state: MI
postal: 48046

有指定的Address模型,我们想把address.yaml内容直接转化成Address对象:

@Setter
@Getter
@ToString
public class Address {private String lines;private String city;private String state;private Integer postal;
}

只需要使用Yaml的loadAs方法即可:

@Test
public void testAddress() throws Exception {Yaml yaml = new Yaml();Address ret = yaml.loadAs(this.getClass().getClassLoader().getResourceAsStream("address.yaml"), Address.class);Assert.assertNotNull(ret);Assert.assertEquals("MI", ret.getState());
}

loadAs方法的第二个参数类型,即是要创建的用于包装yaml数据的类型。
这是第一种方式,对于常见的对象包装其实已经完全足够,我们来看下第二种方式,第二种方式也比较简单,即使用YAML的!!类型强转来完成。这次的类型再复杂一些,我们创建一个Person类型:

@Setter
@Getter
@ToString
public class Person {private String given;private String family;private Address address;
}

这个Person类型包含了我们上一个示例中的Address类型,来添加一个yaml文件:

#person.yaml
--- !!cn.wolfcode.yaml.demo.domain.Person
given  : Chris
family : Dumars
address:lines: |458 Walkman Dr.Suite #292city    : Royal Oakstate   : MIpostal  : 48046

注意第一行,我们使用---代表一个yaml文档的开始,并且立刻使用!!告诉下面的类型为cn.wolfcode.yaml.demo.domain.Person。这样配置之后,我们就可以直接使用load方法来加载对象了:

@Test
public void testPerson() throws Exception {Yaml yaml = new Yaml();Person ret = (Person) yaml.load(this.getClass().getClassLoader().getResourceAsStream("person.yaml"));Assert.assertNotNull(ret);Assert.assertEquals("MI", ret.getAddress().getState());
}

我们直接使用load方法加载对象,并直接转化成Person对象即可。

第三种方式,其实是第一种loadAs方法的实现原理,即在创建Yaml对象时,配置用于映射文档的root构造器。首先去掉person.yaml第一行配置:

#person.yaml
given  : Chris
family : Dumars
address:lines: |458 Walkman Dr.Suite #292city    : Royal Oakstate   : MIpostal  : 48046

实现代码:

@Test
public void testPerson2() {Yaml yaml = new Yaml(new Constructor(Person.class));Person ret = (Person) yaml.load(this.getClass().getClassLoader().getResourceAsStream("person.yaml"));Assert.assertNotNull(ret);Assert.assertEquals("MI", ret.getAddress().getState());
}

可以看到,我们在创建Yaml对象的时候,传入了一个new Constructor(Person.class)对象,即指定了,yaml文件的root对象使用Person类型。注意这个Constructor是org.yaml.snakeyaml.constructor.Constructor对象。

SnakeYaml还能正确的识别集合中的类型。我们修改Person类:

@Setter
@Getter
@ToString
public class Person {private String given;private String family;private List<Address> address;
}

在这里,address属性变成了一个类型安全的List,修改我们的person.yaml文件:

--- !!cn.wolfcode.yaml.demo.domain.Person
given  : Chris
family : Dumars
address:- lines: 458 Walkmancity    : Royal Oakstate   : MIpostal  : 48046- lines: 459 Walkmancity    : Royal Oakstate   : MIpostal  : 48046

我们的address属性由两个address构成,我们来看下这种情况下,是否能正确的识别:

@Test
public void testTypeDesc(){Yaml yaml = new Yaml(new Constructor(Person.class));Person ret = (Person) yaml.load(this.getClass().getClassLoader().getResourceAsStream("person.yaml"));System.out.println(ret);
}

我们来看下输出:
Person(given=Chris, family=Dumars, address=[Address(lines=458 Walkman, city=Royal Oak, state=MI, postal=48046), Address(lines=459 Walkman, city=Royal Oak, state=MI, postal=48046)])
可以看到,确实正确的识别到了address集合中的Address类型。

如果要明确数据类型,可以使用TypeDescription来描述具体的数据类型:

@Test
public void testTypeDesc() {Constructor cons = new Constructor(Person.class);TypeDescription td = new TypeDescription(Person.class);td.putListPropertyType("address", Address.class);cons.addTypeDescription(td);Yaml yaml = new Yaml();Person ret = (Person) yaml.load(this.getClass().getClassLoader().getResourceAsStream("person.yaml"));System.out.println(ret);
}

可以看到,首先创建了一个Person类型的构造器用于映射yaml文档根类型,接着创建了一个TypeDescription,并传入Person类型,代表这个TypeDescription是用来描述Person类型的结构,然后通过putListPropertyType(propertName,propertyType)来指定Person类型的address属性集合中的类型为Address类型,最后将这个类型描述注册到构造器描述中。
TypeDescription类型最常用的两个方法分别是:

public void putListPropertyType(String property, Class<? extends Object> type)
public void putMapPropertyType(String property, Class<? extends Object> key,Class<? extends Object> value)

分别用于限制List集合属性类型和Map集合属性类型,当然,Map类型需要分别指定key和value的值类型。

dump入门

上面简单的介绍了snakeYaml用于yaml文件的解析,下面简单通过几个例子看看怎么使用snakeYaml生成yaml文件。当然,对于yaml来说,更多的时候是作为配置文件存在。

首先我们来看一个简单的生成yaml格式字符串的例子:

@Test
public void testDump1() {Map<String, Object> obj = new HashMap<String, Object>();obj.put("key1", "value1");obj.put("key2", 123);Yaml yaml = new Yaml();StringWriter sw = new StringWriter();yaml.dump(obj, sw);System.out.println(sw.toString());
}

结果输出:

{key1: value1, key2: 123}

代码非常简单,直接使用Yaml的dump方法,就可以把一个对象输出到一个Writer中。我们简单的看一下dump方法的重载:

image.png

 

非常明确,dump用于输出一个对象,而dumpAll和loadAll方法对应,可以输出一组对象。

下面我们来测试一个自定义对象的输出:

@Test
public void testDump2() {Address adr = new Address();adr.setCity("Royal Oak");adr.setLines("458 Walkman");adr.setPostal(48046);adr.setState("MI");Yaml yaml = new Yaml();StringWriter sw = new StringWriter();yaml.dump(adr, sw);System.out.println(sw.toString());
}

输出结果为:
!!cn.wolfcode.yaml.demo.domain.Address {city: Royal Oak, lines: 458 Walkman, postal: 48046,
state: MI}

接下来再来演示一个输出多个对象的情况:

@Test
public void testDump3() {Address adr = new Address();adr.setCity("Royal Oak");adr.setLines("458 Walkman");adr.setPostal(48046);adr.setState("MI");Address adr2 = new Address();adr2.setCity("Royal Oak");adr2.setLines("459 Walkman");adr2.setPostal(48046);adr2.setState("MI");List<Address> target=new ArrayList<>();target.add(adr);target.add(adr2);Yaml yaml = new Yaml();StringWriter sw = new StringWriter();yaml.dumpAll(target.iterator(), sw);System.out.println(sw.toString());
}

输出结果为:

!!cn.wolfcode.yaml.demo.domain.Address {city: Royal Oak, lines: 458 Walkman, postal: 48046,
state: MI}
--- !!cn.wolfcode.yaml.demo.domain.Address {city: Royal Oak, lines: 459 Walkman, postal: 48046,
state: MI}
符合预期。

当然,关于dump方法的更多使用,比如设置生成样式的DumperOptions,设置Tag格式的Representer等更高级一些的需求,大家可以查看SnakeYaml的开发文档:https://bitbucket.org/asomov/snakeyaml/wiki/Documentation



 

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

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

相关文章

有源代码的iphone项目

2019独角兽企业重金招聘Python工程师标准>>> http://blog.joomla.org.tw/iphone-ipad/104-iphone.html 學習和利用現成的資源是很重要的&#xff0c;以下列出有原始碼可下載的iPhone/iPod程式&#xff0c;這邊收集的是以已經放到App Store上的程式為主&#xff0c;…

Content Security Policy 入门教程

From: http://www.ruanyifeng.com/blog/2016/09/csp.html 跨域脚本攻击 XSS 是最常见、危害最大的网页安全漏洞。 为了防止它们&#xff0c;要采取很多编程措施&#xff0c;非常麻烦。很多人提出&#xff0c;能不能根本上解决问题&#xff0c;浏览器自动禁止外部注入恶意脚本&…

springboot跨域配置

From: https://www.cnblogs.com/nananana/p/8492185.html 前言&#xff1a; 当它请求的一个资源是从一个与它本身提供的第一个资源的不同的域名时&#xff0c;一个资源会发起一个跨域HTTP请求(Cross-site HTTP request)。 比如说&#xff0c;域名A ( http://domaina.example …

l2正则化

在机器学习中&#xff0c;无论是分类还是回归&#xff0c;都可能存在由于特征过多而导致的过拟合问题。当然解决的办法有 &#xff08;1&#xff09;减少特征&#xff0c;留取最重要的特征。 &#xff08;2&#xff09;惩罚不重要的特征的权重。 但是通常情况下&#xff0c;我们…

机房收费系统的合作版

概述 机房收费系统的合作版自己负责的是B层和Facade层&#xff0c;在做这块的时候有很多的感触&#xff1a;动态SQL语句&#xff1b;设计模式&#xff1b;合作开发应该注意的点。其中动态SQL语句的理解已经在上一篇博客中写了&#xff0c;如果你有意向的话&#xff0c;可以看一…

ajax跨域,这应该是最全的解决方案了

From: https://segmentfault.com/a/1190000012469713 前言 从刚接触前端开发起&#xff0c;跨域这个词就一直以很高的频率在身边重复出现&#xff0c;一直到现在&#xff0c;已经调试过N个跨域相关的问题了&#xff0c;16年时也整理过一篇相关文章&#xff0c;但是感觉还是差…

如何导入ShareSDK的sample

由于项目需要&#xff0c;最近需要做10几个平台的分享&#xff0c;如果自己去集成&#xff0c;浪费很多时间&#xff0c;而且还很难成功。最后发现Sharesdk,可以满足项目需求。 首先&#xff0c;需要到他们的官网http://sharesdk.cn/下载android版本的SDK。 然后玩了一下他们的…

EF5.x Code First 一对多关联条件查询,Contains,Any,All

背景 通过多个部门id获取所有用户&#xff0c;部门和用户是多对多。 已知部门id&#xff0c;获取该部门包括该部门下的所有子部门的所有用户。 关系如下&#xff1a; public class Entity:IEntity{public Guid Id { get; set; }public string CreateUser { get; set; }public D…

Spring5:@Autowired注解、@Resource注解和@Service注解

From: https://www.cnblogs.com/szlbm/p/5512931.html 什么是注解 传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop、事物&#xff0c;这么做有两个缺点&#xff1a; 1、如果所有的内容都配置在.xml文件中&#xff0c;那么.xml文件将会十分庞大&#xff1b;如…

CCNA实验(8) -- PPP HDLC

HDLC帧格式与以太帧格式有很大差别&#xff0c;HDLC帧没有源MAC和目的MAC地址。HDLC不能提供验证&#xff0c;缺少对链路保护。Cisco设备与Cisco设备连接&#xff0c;可用HDLC封装。Cisco设备与非Cisco设备连接&#xff0c;应使用PPP协议。PPP经过4个过程在点到点链路上建立连接…

不使用中间变量交换2个数据

2019独角兽企业重金招聘Python工程师标准>>> 第一种方法&#xff1a; <!-- lang: cpp -->aab;ba-b;aa-b;可能产生越界和溢出。 第二种方法&#xff1a; <!-- lang: cpp -->aa^b;ba^b;aa^b;这种方法只适用整形数。 写成宏的形式 <!-- lang: cpp -->…

slf4j的简单用法以及与log4j的区别

From: https://www.cnblogs.com/qlqwjy/p/9275415.html 之前在项目中用的日志记录器都是log4j的日志记录器&#xff0c;可是到了新公司发现都是slf4j&#xff0c;于是想着研究一下slf4j的用法。 注意:每次引入Logger的时候注意引入的jar包&#xff0c;因为有Logger的包太多了。…

JdbcType类型和Java类型的对应关系

From: https://www.cnblogs.com/tongxuping/p/7134113.html 在Oracle中有些字段不是必填时在用户使用的时候会出现数据null的情况。这个时候在Oracle中是无法进行插入的。 1 JDBC Type Java Type 2 CHAR String 3 VARCHAR String 4 L…

MyBatis Generator配置文件翻译

From: https://www.cnblogs.com/GaiDynasty/p/4088531.html <classPathEntry> 驱动文件指定配置项 <classPathEntry location"/Program Files/IBM/SQLLIB/java/db2java.zip" /> <columnOverride> 将数据库中的字段重命名为实体类的属性 colu…

SpringBoot系列十:SpringBoot整合Redis

From: https://www.cnblogs.com/leeSmall/p/8728231.html 声明&#xff1a;本文来源于MLDN培训视频的课堂笔记&#xff0c;写在这里只是为了方便查阅。 1、概念&#xff1a;SpringBoot 整合 Redis 2、背景 Redis 的数据库的整合在 java 里面提供的官方工具包&#xff1a;j…

海贼王革命家—龙—实力到底如何?

龙——整个海贼王世界中最神秘的人物&#xff0c;令世界政府最担心的存在&#xff0c;是所有迷最为期待的实力展现&#xff0c;他的身上好像有着无数的秘密等着尾田为我们揭晓。 路飞的父亲——未来的海贼王、卡普的儿子——海军英雄、革民军首领——唯一可以跟世界政府抗衡的组…

MyBatis 实践

From&#xff1a; https://www.cnblogs.com/luyiba/p/6303717.html MyBatis简介 MyBatis前身是iBatis,是一个基于Java的数据持久层/对象关系映射(ORM)框架. MyBatis是对JDBC的封装,使开发人员只需关注SQL本身,而不需花费过多的精力去处理如注册驱动、设置参数、创建Connectio…

皮克斯背后新技术

2019独角兽企业重金招聘Python工程师标准>>> 皮克斯每创作一部动画作品总会给观众带来或多或少的惊喜&#xff0c;而很多影视动画从业人员也习惯于关注他们的每一部作品的制作&#xff0c;因为新技术往往就在这些制作过程中诞生&#xff0c;如今皮克斯动画已经成为C…

数据结构:二叉查找树(C语言实现)

数据结构&#xff1a;二叉查找树 二叉查找树 基础知识 关于二叉树的基础知识&#xff0c;请看我的一篇博客:二叉树的链式存储 二叉查找树的特征 二叉查找树或者是一棵空树&#xff0c;或者是具有下列性质的二叉树&#xff1a;  1.若其左子树不空&#xff0c;则左子树上所有结…

Effective Java 电子书 apk版本下载

下载安装包以后&#xff0c;安装即可阅读该书了&#xff0c;并且实时展示每章节代码哦&#xff0c;并且可以运行哦&#xff0c;赶快下载体验吧. Effective Java中文第二版下载地址&#xff1a;下载 应用截图&#xff1a; 转载于:https://www.cnblogs.com/spring87/p/6090010.ht…