[英]Jackson YAML: support for anchors and references
我正在研究將 YAML 用於有點復雜的元數據語言。 如果我們可以使用YAML 的錨點和引用,將有助於使文檔更小、更簡單。 我編寫了一些測試代碼,似乎表明 Jackson 的 YAML 實現不支持此功能(和/或未顯示 SnakeYAML 對此功能的支持)。
這是我的測試 YAML 文件:
set_one:
bass: tama rockstar 22x16
snare: &ludwig ludwig supralight 6.5x15
tom1: tama rockstar 12x11
tom2: tama rockstar 16x16
set_two:
snare: *ludwig
我像這樣解析這個文件:
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
FileInputStream fis = null;
try
{
fis = new FileInputStream(file);
JsonNode nodeTree = mapper.readTree(fis);
examineObject(nodeTree, 0);
}
...
這是我的“examineObject()”方法的輸出(你可能猜到它是做什么的):
key = "set_one", type = OBJECT
key = "bass", type = STRING, value = "tama rockstar 22x16"
key = "snare", type = STRING, value = "ludwig supralight 6.5x15"
key = "tom1", type = STRING, value = "tama rockstar 12x11"
key = "tom2", type = STRING, value = "tama rockstar 16x16"
key = "set_two", type = OBJECT
key = "snare", type = STRING, value = "ludwig"
很明顯,有足夠的知識可以從“set_one.snare”中省略錨值,但是在調試器中,我無法在 JsonNode 的任何位置找到該元素的值。 真正的問題是“set_two.snare”的值只是“ludwig”。 引用符號 ('*') 已被刪除,但值是引用的值,而不是引用的元素。
我使用的是 Jackson 2.8.3 版和 SnakeYaml 1.17 版。 我只能使用 Jackson,因為這只是一個更大項目的一部分,該項目已經將 Jackson 用於 JSON。
我真正想要的是 Jackson 是否可以自動解析引用並制作引用值的副本。 在我的示例中,這意味着“set_two.snare”的值將是“ludwig supralight 6.5x15”。
如果我不能得到我的第一選擇,那么我希望 Jackson 保留錨點和引用,以便我可以手動對節點樹進行后處理並自己解析引用。 例如,當我看到“set_two.snare”的值為“*ludwig”時,我可以在樹中搜索錨點為“&ludwig”的節點,然后復制該節點。
如果有答案,我覺得它可能會以某種方式涉及“com.fasterxml.jackson.dataformat.yaml.YAMLParser.Feature”類。 不幸的是,我找不到任何有關功能(如果存在)的文檔,這些文檔將啟用我正在尋找的行為。
首先,傑克遜實際上確實支持 YAML 錨點和引用,至少在某種程度上他們與傑克遜如何使用@JsonIdentityInfo
支持對象 Id 引用一起@JsonIdentityInfo
:限制是你不能 - 例如 - 引用一個鍵/值對 am Object .
但是,僅對通過使用@JsonIdentityInfo
注釋 then 指定的類型和屬性啟用標識 ID/引用處理。 因此,您必須注釋可能被引用的類型或屬性(無需同時進行)。
這里可能有幫助的一件事是考慮傑克遜處理的對象 ID 對於所有格式都非常相似:因此,盡管jackson-dataformat-yaml
確實公開了 YAML 具有(而 JSON 沒有)的“本機”對象(和類型)ID ,數據綁定級別的處理是相同的。 因此,如果您可以使 Object Id/References 與 JSON(它添加額外的 id 屬性)一起使用,它也將與 YAML 一起使用。
還有一件額外的事情是相關的: YAMLParser.Feature.USE_NATIVE_OBJECT_ID
它決定了在編寫 YAML 時引用和 id 的表達方式——默認情況下,它使用本機錨點,但可以關閉它以使用“類似 JSON”的普通屬性.
我希望這會有所幫助。 要獲得更多幫助,最好的地方是jackson-users
郵件列表。
由於 Jackson YAML 不支持 Anchors 和引用(issue ),最好回退到 SnakeYaml 來解析 YAML 文件,然后將其轉換為 Jackson 的格式以利用 Jackson 的靈活性優勢。 Snake Yaml 支持錨點,與 Jackson 不同(盡管 Jackson 在后台使用 snakeyaml 來解析 Yaml 文件)。
import java.io.{File, FileInputStream, FileReader}
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.databind.{JsonNode, ObjectMapper}
import org.yaml.snakeyaml.Yaml
// Parsing the YAML file with SnakeYAML - since Jackson Parser does not support Anchors and references
val ios = new FileInputStream(new File(yamlFilePath))
val yaml = new Yaml()
val mapper = new ObjectMapper().registerModules(DefaultScalaModule)
val yamlObj = yaml.loadAs(ios, classOf[Any])
// Converting the YAML to Jackson YAML - since it has more flexibility
val jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(yamlObj) // Formats YAML to a pretty printed JSON string - easy to read
val jsonObj = mapper.readTree(jsonString)
生成的 jsonObj 是一個 JsonNode,它是 Jackson 中的核心數據格式之一。 我們可以使用 as & get 方法輕松遍歷 YAML 文件:
jsonObj.at("/parent/first_level_child/second_level_child")
jsonObj.get("key")
由於 YAML 格式非常接近 JSON 格式,因此在大多數情況下不應該丟失數據。 此外,Jackson 的 JsonNode 格式允許我們使用 Jackson-Json 解析器的額外靈活性——這是 Jackson-YAML 解析器所缺少的。
我只是試圖讓錨點/別名在傑克遜工作......但失敗了。 您可以在此處看到未實現基於別名的 id 支持。 _currentAnchor 實例變量由 getObjectId() 設置和公開,但我沒有找到一種實用的方法來掛鈎 Jackson 以使用該方法。 這不是我第一次與 Jacksons Object-Id 解析架構發生沖突。 建議不要花太多時間在上面。
我的解決方案是直接使用snakeyaml 庫。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.