JAVA基於SnakeYAML實現解析與序列化YAML
這篇文章主要介紹了JAVA基於SnakeYAML實現解析與序列化YAML,文中通過示例程式碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
1.概述
本文,我們將學習如何使用SnakeYAML庫將
YAML文件轉換為Java物件,以及JAVA物件如何序列化為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支援從String或InputStream載入文件,我們從定義一個簡單的YAML文件開始,然後將檔案命名為customer.yaml:
firstName: "John" lastName: "Doe" age: 20
4.1基本用法
現在,我們將使用Yaml類來解析上述YAML文件:
Yaml yaml = new Yaml(); InputStream inputStream = this.getClass() .getClassLoader() .getResourceAsStream("customer.yaml"); Map<String,Object> obj = yaml.load(inputStream); System.out.println(obj);
上面的程式碼生成以下輸出:
{firstName=John,lastName=Doe,age=20}
預設情況下,load()方法返回一個Map物件。查詢Map物件時,我們需要事先知道屬性鍵的名稱,否則容易出錯。更好的辦法是自定義型別。
4.2自定義型別解析
SnakeYAML提供了一種將文件解析為自定義型別的方法
讓我們定義一個Customer類,然後嘗試再次載入該文件:
public class Customer { private String firstName; private String lastName; private int age; // getters and setters }
現在我麼來載入:
Yaml yaml = new Yaml(); InputStream inputStream = this.getClass() .getClassLoader() .getResourceAsStream("customer.yaml"); Customer customer = yaml.load(inputStream);
還有一種方法是使用Constructor:
Yaml yaml = new Yaml(new Constructor(Customer.class));
4.3隱式型別
如果沒有為給定屬性定義型別,則庫會自動將值轉換為隱式type。
例如:
1.0 -> Float 42 -> Integer 2009-03-30 -> Date
讓我們使用一個TestCase來測試這種隱式型別轉換:
@Test public void whenLoadYAML_thenLoadCorrectImplicitTypes() { Yaml yaml = new Yaml(); Map<Object,Object> document = yaml.load("3.0: 2018-07-22"); assertNotNull(document); assertEquals(1,document.size()); assertTrue(document.containsKey(3.0d)); }
4.4 巢狀物件
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類:
public class Customer { private String firstName; private String lastName; private int age; private List<Contact> contactDetails; private Address homeAddress; // getters and setters } public class Contact { private String type; private int number; // getters and setters } public class Address { private String line; private String city; private String state; private Integer zip; // getters and setters }
現在,我們來測試下Yaml#load():
@Test public void whenLoadYAMLDocumentWithTopLevelClass_thenLoadCorrectJavaObjectWithNestedObjects() { Yaml yaml = new Yaml(new Constructor(Customer.class)); InputStream inputStream = this.getClass() .getClassLoader() .getResourceAsStream("yaml/customer_with_contact_details_and_address.yaml"); Customer customer = yaml.load(inputStream); 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()); }
4.5型別安全的集合
當給定Java類的一個或多個屬性是泛型集合類時,需要通過TypeDescription來指定泛型型別,以以便可以正確解析。
讓我們假設一個 一個Customer擁有多個Contact:
firstName: "John" lastName: "Doe" age: 31 contactDetails: - { type: "mobile",number: 123456789} - { type: "landline",number: 123456789}
為了能正確解析,我們可以在頂級類上為給定屬性指定TypeDescription :
Constructor constructor = new Constructor(Customer.class); TypeDescription customTypeDescription = new TypeDescription(Customer.class); customTypeDescription.addPropertyParameters("contactDetails",Contact.class); constructor.addTypeDescription(customTypeDescription); Yaml yaml = new Yaml(constructor);
4.6載入多個檔案
在某些情況下,單個檔案中可能有多個YAML文件,而我們想解析所有文件。所述YAML類提供了一個LOADALL()方法來完成這種型別的解析。
假設下面的內容在一個檔案中:
--- firstName: "John" lastName: "Doe" age: 20 --- firstName: "Jack" lastName: "Jones" age: 25
我們可以使用loadAll()方法解析以上內容,如以下程式碼示例所示:
@Test public void whenLoadMultipleYAMLDocuments_thenLoadCorrectJavaObjects() { Yaml yaml = new Yaml(new Constructor(Customer.class)); InputStream inputStream = this.getClass() .getClassLoader() .getResourceAsStream("yaml/customers.yaml"); int count = 0; for (Object object : yaml.loadAll(inputStream)) { count++; assertTrue(object instanceof Customer); } assertEquals(2,count); }
5.生成YAML檔案
SnakeYAML 支援 將java物件序列化為yml。
5.1基本用法
我們將從一個將Map <String,Object>的例項轉儲到YAML文件(String)的簡單示例開始:
@Test public 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"; assertEquals(expectedYaml,writer.toString()); }
上面的程式碼產生以下輸出(請注意,使用LinkedHashMap的例項將保留輸出資料的順序):
name: Silenthand Olleander race: Human traits: [ONE_HAND,ONE_EYE]
5.2自定義Java物件
我們還可以選擇將自定義Java型別轉儲到輸出流中。
@Test public 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.baeldung.snakeyaml.Customer {age: 45,contactDetails: null,firstName: Greg,\n homeAddress: null,lastName: McDowell}\n"; assertEquals(expectedYaml,writer.toString()); }
生成內容會包含!!com.baeldung.snakeyaml.Customer,為了避免在輸出檔案中使用標籤名,我們可以使用庫提供的 dumpAs()方法。
因此,在上面的程式碼中,我們可以進行以下調整以刪除標記:
yaml.dumpAs(customer,Tag.MAP,null);
六 結語
本文說明了SnakeYAML庫解析和序列化YAML文件。
所有示例都可以在GitHub專案中找到。
英文原文: Parsing YAML with SnakeYAML
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。