Content Table

Java 操作 Yaml

Java 里可以使用类 Yaml 序列化和反序列化 Bean,有 2 个反序列化 Yaml 文件为 Java Bean 的方式:

  • 在 Yaml 的构造函数中指定 Bean 的类型,然后调用方法 load() 生成 Bean:

    1
    2
    Yaml yaml = new Yaml(new Constructor(User.class));
    User user = yaml.load(inputStream);
  • 使用 Yaml 的默认构造函数,然后调用方法 loadAs() 生成 Bean:

    1
    2
    Yaml yaml = new Yaml();
    User user = yaml.loadAs(inputStream, User.class);
  • 需要注意的是,下面的代码报错:

    1
    2
    Yaml yaml = new Yaml();
    User user = yaml.load(inputStream); // Error: java.util.LinkedHashMap cannot be cast to yaml.User

下面就以类 User 以及类把 User 作为属性时的多种情况为例进行演示,其中:

  • Yaml 反序列化为 User 的代码是一样的
  • Yaml 文件的写法需要注意

User

1
2
3
4
5
6
7
8
9
10
11
12
package yaml;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class User {
private int id;
private String name;
private String nickName;
}

对应的 Yaml 文件 user.yml:

1
2
3
4
5
id: 10
name: Biao

# User 中没有属性 wo,报错: Cannot create property=wo for JavaBean=yaml.User@2d6d8735
# wo: PK

注意: 在 yaml 文件中的属性如果在类中不存在,反序列化时会抛异常。类中的属性在 Yaml 文件里没有,则没有问题。

UserHolder

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package yaml;

import lombok.Getter;
import lombok.Setter;

import java.util.List;
import java.util.Map;

@Getter
@Setter
public class UserHolder {
private User john;
private List<User> users;
private Map<String, User> userMap;
}

对应的 Yaml 文件 user-holder.yml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# private User john
john: # field name
id: 13 # bean's field
name: John # bean's field
nickName: Bobi # 不能写为 nick-name,这是因为 Spring Boot 作了特殊处理

# private List<User> users
# 对象数组使用下面 2 种格式都可以
users:
- id: 14 # bean's field
name: Jack # bean's field
-
id: 15
name: Sophie

# private Map<String, User> userMap
userMap: # field name (注意不能用 user-map,这种方式是 SpringBoot 对 Yaml 进行了改造)
Alice: # map key
id: 10 # map value is bean, bean's field
name: Alice # map value is bean, bean's field
Bob:
id: 11
name: Bob

UserTest

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package yaml;

import com.alibaba.fastjson.JSON;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;

import java.io.IOException;
import java.io.InputStream;

public class UserTest {
public static void main(String[] args) throws IOException {
unmarshalUserTest1();
unmarshalUserTest2();
unmarshalUserHolderTest();
}

public static void unmarshalUserTest1() {
Yaml yaml = new Yaml(new Constructor(User.class));
InputStream in = ClassLoader.getSystemResourceAsStream("user.yml"); // 找不到返回 null
User user = yaml.load(in);

System.out.println(JSON.toJSONString(user));
}

public static void unmarshalUserTest2() throws IOException {
Yaml yaml = new Yaml();
InputStream in = ClassLoader.getSystemResourceAsStream("user.yml"); // 找不到返回 null
User user = yaml.loadAs(in, User.class);

System.out.println(JSON.toJSONString(user));
}

public static void unmarshalUserHolderTest() {
Yaml yaml = new Yaml(new Constructor(UserHolder.class));
InputStream in = ClassLoader.getSystemResourceAsStream("user-holder.yml");
UserHolder user = yaml.load(in);

System.out.println(JSON.toJSONString(user, true));
}
}

忽略不识别的属性

有 Yaml 中存在,Bean 不存在的属性时,反序列化会报错,可以使用 Representer 设置忽略不存在的属性解决这个问题:

1
2
3
Representer representer = new Representer();
representer.getPropertyUtils().setSkipMissingProperties(true);
Yaml yaml = new Yaml(new Constructor(UserHolder.class), representer);