Springboot底层-snakeyaml的使用

所用依赖

目前最稳定的版本为1.25版,最新版为1.28版。

下载链接:

  • 来源:http://bitbucket.org/asomov/snakeyaml/src

  • JAR包:https://repo1.maven.org/maven2/org/yaml/snakeyaml/1.25/snakeyaml-1.25.jar

  • Android包:https://repo1.maven.org/maven2/org/yaml/snakeyaml/1.25/snakeyaml-1.25-android.jar

  • 储存库:http://search.maven.org/#search|ga|1|snakeyaml

发行版在中央存储库中可用。

依赖项定义(在pom.xml中)

<dependencies>
  ...
  <dependency>
    <groupId>org.yaml</groupId>
    <artifactId>snakeyaml</artifactId>
    <version>1.26-SNAPSHOT</version>
  </dependency>
  ...
</dependencies>

Android项目的依赖项定义

<dependency>
  <groupId>org.yaml</groupId>
  <artifactId>snakeyaml</artifactId>
  <version>1.26-SNAPSHOT</version>
  <classifier>android</classifier>
</dependency>

使用教程

首先实例化org.yaml.snakeyaml.Yaml实例。

Yaml yaml = new Yaml();

加载YAML

方法yaml.load()可以将YAML文档转换为Java对象。

Yaml yaml = new Yaml();
String document = "\n- Hesperiidae\n- Papilionidae\n- Apatelodidae\n- Epiplemidae";
List<String> list = (List<String>) yaml.load(document);
System.out.println(list);

yaml.load()接受String或InputStream对象。yaml.load(InputStream stream)通过检查流开始处的BOM(字节顺序标记)序列来检测编码。如果没有BOM,则假定为utf-8编码。

yaml.load()返回一个Java对象。

public void testLoadFromString() {
    Yaml yaml = new Yaml();
    String document = "hello: 25";
    Map map = (Map) yaml.load(document);
    assertEquals("{hello=25}", map.toString());
    assertEquals(new Long(25), map.get("hello"));
}

public void testLoadFromStream() throws FileNotFoundException {
    InputStream input = new FileInputStream(new File("src/test/resources/reader/utf-8.txt"));
    Yaml yaml = new Yaml();
    Object data = yaml.load(input);
    assertEquals("test", data);
    //
    data = yaml.load(new ByteArrayInputStream("test2".getBytes()));
    assertEquals("test2", data);
}

如果字符串或流包含多个文档,则可以使用yaml.loadAll()方法将它们全部加载。

---
Time: 2001-11-23 15:01:42 -5
User: ed
Warning:
  This is an error message
  for the log file
---
Time: 2001-11-23 15:02:31 -5
User: ed
Warning:
  A slightly different error
  message.
---
Date: 2001-11-23 15:03:17 -5
User: ed
Fatal:
  Unknown variable "bar"
Stack:
  - file: TopClass.py
    line: 23
    code: |
      x = MoreObject("345\n")
  - file: MoreClass.py
    line: 58
    code: |-
      foo = bar
public void testLoadManyDocuments() throws FileNotFoundException {
    InputStream input = new FileInputStream(new File(
            "src/test/resources/specification/example2_28.yaml"));
    Yaml yaml = new Yaml();
    int counter = 0;
    for (Object data : yaml.loadAll(input)) {
        System.out.println(data);
        counter++;
    }
    assertEquals(3, counter);
}
{Time=Fri Nov 23 21:01:42 CET 2001, User=ed, Warning=This is an error message for the log file}
{Time=Fri Nov 23 21:02:31 CET 2001, User=ed, Warning=A slightly different error message.}
{Date=Fri Nov 23 21:03:17 CET 2001, User=ed, Fatal=Unknown variable "bar", Stack=[{file=TopClass.py, line=23, code=x = MoreObject("345\n")
}, {file=MoreClass.py, line=58, code=foo = bar}]}

仅在调用迭代器时才对文档进行解析(懒加载)。

SnakeYAML允许您构造任何类型的Java对象。

none: [~, null]
bool: [true, false, on, off]
int: 42
float: 3.14159
list: [LITE, RES_ACID, SUS_DEXT]
map: {hp: 13, sp: 5}
public void testLoad() throws IOException {
    String doc = Util.getLocalResource("examples/any-object-example.yaml");
    Yaml yaml = new Yaml();
    Map<String, Object> object = (Map<String, Object>) yaml.load(doc);
    System.out.println(object);
}
{none=[null, null], bool=[true, false, true, false], int=42, float=3.14159, 
list=[LITE, RES_ACID, SUS_DEXT], map={hp=13, sp=5}}

甚至可以构造自定义Java类的实例。

/**
 * create JavaBean
 */
public void testGetBeanAssumeClass() {
    String data = "--- !org.yaml.snakeyaml.constructor.Person\nfirstName: Andrey\nage: 99";
    Object obj = construct(data);
    assertNotNull(obj);
    assertTrue("Unexpected: " + obj.getClass().toString(), obj instanceof Person);
    Person person = (Person) obj;
    assertEquals("Andrey", person.getFirstName());
    assertNull(person.getLastName());
    assertEquals(99, person.getAge().intValue());
}

/**
 * create instance using constructor arguments
 */
public void testGetConstructorBean() {
    String data = "--- !org.yaml.snakeyaml.constructor.Person [ Andrey, Somov, 99 ]";
    Object obj = construct(data);
    assertNotNull(obj);
    assertTrue(obj.getClass().toString(), obj instanceof Person);
    Person person = (Person) obj;
    assertEquals("Andrey", person.getFirstName());
    assertEquals("Somov", person.getLastName());
    assertEquals(99, person.getAge().intValue());
}

/**
 * create instance using scalar argument
 */
public void testGetConstructorFromScalar() {
    String data = "--- !org.yaml.snakeyaml.constructor.Person 'Somov'";
    Object obj = construct(data);
    assertNotNull(obj);
    assertTrue(obj.getClass().toString(), obj instanceof Person);
    Person person = (Person) obj;
    assertNull("Andrey", person.getFirstName());
    assertEquals("Somov", person.getLastName());
    assertNull(person.getAge());
}

注意:如果要将对象限制为标准Java对象(如List或Long),则需要使用SafeConstructor。

Yaml yaml = new Yaml(new SafeConstructor());

提供顶级类型

它可以加载没有任何显式标签的YAML文档。

invoice: 34843
	date: 2001-01-23
billTo: &id001
    given  : Chris
    family : Dumars
    address:
        lines: |
            458 Walkman Dr.
            Suite #292
        city    : Royal Oak
        state   : MI
        postal  : 48046
shipTo: *id001
product:
    - sku         : BL394D
      quantity    : 4
      description : Basketball
      price       : 450.00
    - sku         : BL4438H
      quantity    : 1
      description : Super Hoop
      price       : 2392.00
tax  : 251.42
total: 4443.52
comments:
    Late afternoon is best.
    Backup contact is Nancy
    Billsmer @ 338-4338.

在“Invoice”,“Person”,“,Address”,“Product”实例中,必须提供对象层次结构中的顶级类:

Yaml yaml = new Yaml(new Constructor(Invoice.class));

SnakeYAML使用Reflection API查找发票上所有属性(设置程序和公共字段)的类。不幸的是,您无法在运行时对类型安全集合进行删除操作。<>之间的类信息仅在编译时可用。

隐式类型

当未明确定义标量节点的标签时,SnakeYAML会尝试检测将正则表达式应用于标量节点内容的类型。

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

类型安全集合

当类型安全(通用)集合是JavaBean的属性时,SnakeYAML会动态检测所需的类。

如果泛型类型是抽象类(接口),则它将不起作用。

您必须在YAML中放置一个显式标签或提供显式TypeDescriptionTypeDescription的目标是收集更多信息并在加载/转储时使用它。

假设文档为如下内容:

plate: 12-XP-F4
wheels:
- {id: 1}
- {id: 2}
- {id: 3}
- {id: 4}
- {id: 5}

现在我们想加载这个类型:

public class Car {
    private String plate;
    private List<Wheel> wheels;

    public String getPlate() {
        return plate;
    }

    public void setPlate(String plate) {
        this.plate = plate;
    }

    public List<Wheel> getWheels() {
        return wheels;
    }

    public void setWheels(List<Wheel> wheels) {
        this.wheels = wheels;
    }
}

其中“wheels”属性是List<Wheel>。为了加载Car(并创建List<Wheel>),您必须提供TypeDescription

Constructor constructor = new Constructor(Car.class);//Car.class is root
TypeDescription carDescription = new TypeDescription(Car.class);
carDescription.putListPropertyType("wheels", Wheel.class);
constructor.addTypeDescription(carDescription);
Yaml yaml = new Yaml(constructor);

这种方式也适用于Map。注意,Map的key和value都可以是任意类型:

plate: 00-FF-Q2
wheels:
  ? {brand: Pirelli, id: 1}
  : 2008-01-16
  ? {brand: Dunkel, id: 2}
  : 2002-12-24
  ? {brand: Pirelli, id: 3}
  : 2008-01-16
  ? {brand: Pirelli, id: 4}
  : 2008-01-16
  ? {brand: Pirelli, id: 5}
  : 2008-01-16

以下是要加载的类:

public class MyCar {
    private String plate;
    private Map<MyWheel, Date> wheels;

    public String getPlate() {
        return plate;
    }

    public void setPlate(String plate) {
        this.plate = plate;
    }

    public Map<MyWheel, Date> getWheels() {
        return wheels;
    }

    public void setWheels(Map<MyWheel, Date> wheels) {
        this.wheels = wheels;
    }
}

主要代码:

Constructor constructor = new Constructor(MyCar.class);
TypeDescription carDescription = new TypeDescription(MyCar.class);
carDescription.putMapPropertyType("wheels", MyWheel.class, Object.class);
constructor.addTypeDescription(carDescription);
Yaml yaml = new Yaml(constructor);
MyCar car = (MyCar) yaml.load(<文件流>);

转储YAML

Yaml.dump(Object data)方法接受一个Java对象并生成一个YAML文档。

public void testDump() {
    Map<String, Object> data = new HashMap<String, Object>();
    data.put("name", "Silenthand Olleander");
    data.put("race", "Human");
    data.put("traits", new String[] { "ONE_HAND", "ONE_EYE" });
    Yaml yaml = new Yaml();
    String output = yaml.dump(data);
    System.out.println(output);
}
name: Silenthand Olleander
traits: [ONE_HAND, ONE_EYE]
race: Human

Yaml.dump(Object data, Writer output)会将生成的YAML文档写入指定的文件/流。

public void testDumpWriter() {
    Map<String, Object> data = new HashMap<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);
    System.out.println(writer.toString());
}

如果需要将多个YAML文档转储在同一个文件/流中,请使用yaml.dumpAll(Iterator<Object> data)方法。它接受要序列化为YAML文档的Java对象的迭代器。也可以使用Writer。

public void testDumpMany() {
    List<Integer> docs = new LinkedList<Integer>();
    for (int i = 1; i < 4; i++) {
        docs.add(i);
    }
    DumperOptions options = new DumperOptions();
    options.explicitStart(true);
    Yaml yaml = new Yaml(options);
    System.out.println(yaml.dump(docs));
    System.out.println(yaml.dumpAll(docs.iterator()));
}
--- [1, 2, 3]

--- 1
--- 2
--- 3

您也可以转储JavaBean。

public void testDumpCustomJavaClass() {
    Hero hero = new Hero("Galain Ysseleg", -3, 2);
    Yaml yaml = new Yaml();
    String output = yaml.dump(hero);
    System.out.println(output);
    assertEquals("!!examples.Hero {hp: -3, name: Galain Ysseleg, sp: 2}\n", output);
}
!!examples.Hero {hp: -3, name: Galain Ysseleg, sp: 2}

如你所见,JavaBean的属性按字母顺序排列。

DumperOptions指定转储的格式信息。例如,您可以设置优先级和宽度,使用规范的YAML格式或者对常量和集合强制使用首选样式。

public void testDumperOptions() {
    List<Integer> data = new LinkedList<Integer>();
    for (int i = 0; i < 50; i++) {
        data.add(i);
    }
    Yaml yaml = new Yaml();
    String output = yaml.dump(data);
    System.out.println(output);
    //
    DumperOptions options = new DumperOptions();
    options.setWidth(50);
    options.setIndent(4);
    yaml = new Yaml(options);
    output = yaml.dump(data);
    System.out.println(output);
}
[0, 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, 41, 42,
  43, 44, 45, 46, 47, 48, 49]

[0, 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, 41, 42, 43, 44, 45, 46, 47, 48, 49]

规范格式:

public void testDumperOptionsCanonical() {
    List<Integer> data = new LinkedList<Integer>();
    for (int i = 0; i < 5; i++) {
        data.add(i);
    }
    DumperOptions options = new DumperOptions();
    options.setCanonical(true);
    Yaml yaml = new Yaml(options);
    String output = yaml.dump(data);
    System.out.println(output);
}
---
!!seq [
  !!int "0",
  !!int "1",
  !!int "2",
  !!int "3",
  !!int "4",
]
public void testDumperOptionsFlowStyle() {
    List<Integer> data = new LinkedList<Integer>();
    for (int i = 0; i < 5; i++) {
        data.add(i);
    }
    DumperOptions options = new DumperOptions();
    options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
    Yaml yaml = new Yaml(options);
    String output = yaml.dump(data);
    System.out.println(output);
}
- 0
- 1
- 2
- 3
- 4
public void testDumperOptionsStyle() {
    List<Integer> data = new LinkedList<Integer>();
    for (int i = 0; i < 5; i++) {
        data.add(i);
    }
    DumperOptions options = new DumperOptions();
    options.setDefaultScalarStyle(DumperOptions.ScalarStyle.DOUBLE_QUOTED);
    Yaml yaml = new Yaml(options);
    String output = yaml.dump(data);
    System.out.println(output);
}
- !!int "0"
- !!int "1"
- !!int "2"
- !!int "3"
- !!int "4"

Springboot底层-snakeyaml的使用
https://blog.cikaros.top/doc/5d12e6ae.html
作者
Cikaros
发布于
2021年4月13日
许可协议