Java YAML 序列化
目录
YAML 简介
什么是 YAML ?
-
YAML(YAML Ain't Markup Language,即 YAML 不是一种标记语言),也可以叫做 YML 。YAML 是一种直观的、能够被电脑识别的数据序列化格式,容易被人类阅读,容易和脚本语言交互,可以被支持 YAML 库的不同编程语言程序所导入(如 C/C++、Ruby、Python、Java、Perl、C#、PHP 等)。
-
YML 文件是以数据为核心的,相比 JSON、XML 等方式更加简洁。
-
YAML 文件的扩展名可以使用 .yml 或者 .yaml 。
YAML 语法
- 大小写敏感。
- 数据值前边必须要有空格(大于等于 1 个)作为分隔符。
- 使用缩进表示层级关系。
- 缩进时不允许使用 Tab 键,只允许使用空格(各个系统 Tab对应的 空格数目可能不同,导致层次混乱)。
- 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可。
- # 表示注释,从这个字符一直到行尾,都会被解析器忽略。
YAML 数据格式
- 对象(map):键值对的集合
# 行内写法
address: {province: 山东, city: 济南}
# 多行写法
address:
province: 山东
city: 济南
- 数组:一组按次序排列的值
# 行内写法
hobbyList: [游泳, 跑步]
# 多行写法
hobbyList:
- 游泳
- 跑步
- 纯量:单个的、不可再分的值
# 字符串默认不用加引号,但包含空格或特殊字符必须加引号,单引号或双引号都可以
# 单引号:不识别转移字符,即原样输出
# 双引号:识别转移字符,如 \r、\n 等
userId: S123
username: "lisi"
password: '123456'
province: 山东
city: "济南 : ss"
# 布尔值
success: true
# 整数
age: 13
# 浮点数
weight: 75.5
# Null
gender: ~
# 时间:使用 ISO8601 标准
createDate: 2001-12-14T21:59:43.10+05
- 参数引用:
name: lisi
person:
name: ${name} # 引用上边定义的name值
YAML 序列化
yaml 文件与 Bean 类
示例:yaml 文件
userId: 1
username: lisi
password: 123456
address: {province: 山东, city: 济南}
hobbyList: [游泳, 跑步]
或:
userId: 1
username: "lisi"
password: '123456'
address:
province: 山东
city: "济南 : ss"
hobbyList:
- 游泳
- 跑步
示例:Bean 实体类
- Maven 依赖:
<!-- Bean类的GETTER、SETTER注解 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
- User 实体类:
import lombok.*;
import java.security.Timestamp;
import java.util.List;
@Setter
@Getter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String userId;
private String username;
private String password;
private Timestamp createDate;
private Address address;
private List<String> hobbyList;
}
- Address 实体类:
import lombok.*;
@Setter
@Getter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Address {
private String province;
private String city;
}
snakeyaml 库
Maven 依赖:
<!-- https://mvnrepository.com/artifact/org.yaml/snakeyaml -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.21</version>
</dependency>
1)yaml、map 互转
使用 yaml 对象中的 load 方法会返回一个 map 对象,然后遍历这个 map 即可得到自己想要的数据。
import org.yaml.snakeyaml.Yaml;
import java.io.InputStream;
import java.util.Map;
public class YamlDemo {
public static void main(String[] args) {
// yaml 读取
InputStream in = YamlDemo.class.getClassLoader().getResourceAsStream("test.yaml");
Yaml yaml = new Yaml();
Map<String, Object> map = yaml.loadAs(in, Map.class);
map.forEach(
(String key, Object value) -> {
System.out.println("key: "+key+" value: "+value);
}
);
/* 执行结果:
key: userId value: 1
key: username value: lisi
key: password value: 123456
key: address value: {province=山东, city=济南}
key: hobbyList value: [游泳, 跑步]
*/
// yaml 写入
map.put("username", "zhangsan"); // 修改读取的yaml内容
try {
// 将修改后的内容写入new_user.yaml
yaml.dump(map, new OutputStreamWriter(new FileOutputStream(new File("new_user.yaml"))));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
执行结果:
key: userId value: 1
key: username value: lisi
key: password value: 123456
key: address value: {province=山东, city=济南}
key: hobbyList value: [游泳, 跑步]
2)yaml 转 Bean
import org.yaml.snakeyaml.Yaml;
import java.io.*;
import java.util.Objects;
public class YamlDemo {
public static void main(String[] args) {
InputStream resource = YamlDemo.class.getClassLoader().getResourceAsStream("test.yaml");
if (Objects.nonNull(resource)) {
Yaml yaml = new Yaml();
User user = yaml.loadAs(resource, User.class);
System.out.println(user.getClass()); // class User
System.out.println(user); // User(userId=1, username=lisi, password=123456, createDate=null, address=Address(province=山东, city=济南), hobbyList=[游泳, 跑步])
}
}
}
3)Bean 转 yaml
import org.yaml.snakeyaml.Yaml;
import java.io.*;
import java.util.Arrays;
public class YamlDemo {
public static void main(String[] args) {
User user = new User();
user.setUserId("1");
user.setUsername("lisi");
user.setPassword("123456");
user.setAddress(new Address("山东", "济南"));
user.setHobbyList(Arrays.asList("游泳", "跑步"));
Yaml yaml = new Yaml();
String userString = yaml.dump(user); // 输出字符串
try {
yaml.dump(user, new FileWriter("Bean.yaml")); // 输出文件
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(userString);
System.out.println(yaml.loadAs(userString, User.class));
}
}
输出结果:
!!User # 首行为:!!+全类名
address: {city: 济南, province: 山东}
createDate: null
hobbyList: [游泳, 跑步]
password: '123456'
userId: '1'
username: lisi
上面的对象和数组是显示在一行的,我们也可以通过自定义序列化显示为多行。
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import java.io.*;
import java.util.Arrays;
public class YamlDemo {
public static void main(String[] args) {
User user = new User();
user.setUserId("1");
user.setUsername("lisi");
user.setPassword("123456");
user.setAddress(new Address("山东", "济南"));
user.setHobbyList(Arrays.asList("游泳", "跑步"));
DumperOptions dumperOptions = new DumperOptions();
dumperOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
Yaml yaml = new Yaml(dumperOptions);
String userString = yaml.dump(user); // 输出字符串
try {
yaml.dump(user, new FileWriter("Bean.yaml")); // 输出文件
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(userString);
System.out.println(yaml.loadAs(userString, User.class));
}
}
执行结果:
!!User
address:
city: 济南
province: 山东
createDate: null
hobbyList:
- 游泳
- 跑步
password: '123456'
userId: '1'
username: lisi
jackson 库
jackson-dataformat-yaml 是在 snakeyaml 的基础上又封装了一层。
Maven 依赖:
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>2.12.0</version>
</dependency>
1)yaml 转 Bean
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
import java.io.IOException;
import java.io.InputStream;
import java.util.Objects;
public class YamlDemo {
public static void main(String[] args) {
InputStream resource = YamlDemo.class.getClassLoader().getResourceAsStream("test.yaml");
if (Objects.nonNull(resource)) {
YAMLMapper yamlMapper = new YAMLMapper();
User user = null;
try {
user = yamlMapper.readValue(resource, User.class);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(user.getClass()); // class User
System.out.println(user); // User(userId=1, username=lisi, password=123456, createDate=null, address=Address(province=山东, city=济南), hobbyList=[游泳, 跑步])
}
}
}
2)Bean 转 yaml
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
import java.io.FileWriter;
import java.util.Arrays;
public class YamlDemo {
public static void main(String[] args) {
User user = new User();
user.setUserId("1");
user.setUsername("lisi");
user.setPassword("123456");
user.setAddress(new Address("山东", "济南"));
user.setHobbyList(Arrays.asList("游泳", "跑步"));
YAMLMapper yamlMapper = new YAMLMapper();
try {
System.out.println(yamlMapper.writeValueAsString(user));
yamlMapper.writeValue(new FileWriter("Bean.yaml"), user);
} catch (Exception e) {
e.printStackTrace();
}
}
}
执行结果:
---
userId: "1"
username: "lisi"
password: "123456"
createDate: null
address:
province: "山东"
city: "济南"
hobbyList:
- "游泳"
- "跑步"