簡體   English   中英

從代表不同類的多個 YAML 文檔中解析單個 POJO

[英]Parse a single POJO from multiple YAML documents representing different classes

我想使用一個包含多個不同對象的 YAML 文件 - 用於不同的應用程序。 I need to fetch one object to get an instance of MyClass1, ignoring the rest of docs for MyClass2, MyClass3, etc. Some sort of selective de-serializing: now this class, then that one... The structure of MyClass2, MyClass3 is使用 MyClass1 的應用程序完全不知道。 當然,該文件始終是有效的 YAML。

YAML 可以是我們實現這種多類容器所需的任何結構。 首選的解析工具是snakeyaml。

明智嗎? 我怎樣才能忽略除一個 object 之外的所有內容?

UPD:將所有“文檔”替換為“對象”。 我認為我們必須談論包含多個不同結構對象的單個 YAML 文檔。 更多的是,解析器只知道 1 個結構,並想忽略 rest。

UDP2:我認為使用snakeyaml 是不可能的。 無論如何,我們必須讀取所有對象 - select 是稍后需要的。 但也許我錯了。

UPD2:示例配置文件

--- 
- 
  exportConfiguration781: 
    attachmentFieldName: "name"
    baseSftpInboxPath: /home/user/somedir/
    somebool: false
    days: 9999
    expected: 
      - ABC w/o quotes
      - "Cat ABC"
      - "Some string"
    dateFormat: yyyy-MMdd-HHmm
    user: someuser
- 
  anotherConfiguration: 
    k1: v1
    k2: 
      - v21
      - v22

使用 SnakeYAML 絕對可以做到這一點,盡管這不是微不足道的。 這是您需要做的一般綱要:

首先,讓我們看看使用 SnakeYAML 進行加載的作用。 這是YAML class 的重要部分:

private Object loadFromReader(StreamReader sreader, Class<?> type) {
    Composer composer = new Composer(new ParserImpl(sreader), resolver, loadingConfig);
    constructor.setComposer(composer);
    return constructor.getSingleData(type);
}

作曲家將 YAML 輸入解析為Nodes 為此,它不需要任何關於類結構的知識,因為每個節點都是 ScalarNode、SequenceNode 或 MappingNode,它們只代表 YAML 結構。

構造函數獲取composer生成的根節點並從中生成本地 POJO。 因此,您要做的是在節點圖的某些部分到達構造函數之前丟棄它們。

最簡單的方法可能是從Composer派生並覆蓋兩個這樣的方法:

public class MyComposer extends Composer {
    private final int objIndex;

    public MyComposer(Parser parser, Resolver resolver, int objIndex) {
        super(parser, resolver);
        this.objIndex = objIndex;
    }

    public MyComposer(Parser parser, Resolver resolver, LoaderOptions loadingConfig, int objIndex) {
        super(parser, resolver, loadingConfig);
        this.objIndex = objIndex;
    }


    @Override
    public Node getNode() {
        return strip(super.getNode());
    }

    private Node strip(Node input) {
        return ((SequenceNode)input).getValue().get(objIndex);
    }
}

strip實現只是一個例子。 在這種情況下,我假設您的 YAML 看起來像這樣(對象內容是任意的):

- {first: obj}
- {second: obj}
- {third: obj}

而您只需 select 和 object 您實際上想要按序列中的索引反序列化。 但是你也可以有更復雜的東西,比如搜索算法。

現在你有了自己的作曲家,你可以做

Constructor constructor = new Constructor();
// assuming we want to get the object at index 1 (i.e. second object)
Composer composer = new MyComposer(new ParserImpl(sreader), new Resolver(), 1);
constructor.setComposer(composer);
MyObject result = (MyObject)constructor.getSingleData(MyObject.class);

@flyx 的答案對我很有幫助,通過覆蓋一些方法打開了解決庫(在我們的例子中是snakeyaml)限制的方法。 非常感謝。 很有可能有一個最終的解決方案——但不是現在,此外。 下面的簡單解決方案是健壯的,即使我們找到了完整的庫入侵解決方案,也應該考慮。

我決定通過雙重蒸餾來解決這個任務,抱歉,處理配置文件。 想象后者由幾個部分組成,每個部分都由唯一的標記分隔符標記。 為了保持 YAML-likenes,它可能是

---
#this is a unique key for the configuration A
<some YAML document>
---
#this is another key for the configuration B
<some YAML document

第一遍是預處理。 對於給定的字符串文件字符串和字符串鍵(例如,DELIMITER = "\n---\n"。)我們 select 和 substring 與鍵定義的配置:

int begIndex;                                                                       
do {                                                                                
  begIndex= fileString.indexOf(DELIMITER);                                          
  if (begIndex == -1) {                                                             
    break;                                                                          
  }                                                                                 
  if (fileString.startsWith(DELIMITER + key, begIndex)) {                           
    fileString = fileString.substring(begIndex + DELIMITER.length() + key.length());
    break;                                                                          
  }                                                                                 
  // spoil alien delimiter and repeat search                                        
  fileString = fileString.replaceFirst(DELIMITER, " ");                             
} while (true);                                                                     
int endIndex = fileString.indexOf(DELIMITER);                                       
if (endIndex != -1) {                                                               
  fileString = fileString.substring(0, endIndex);                                   
} 

現在我們將 fileString 提供給簡單的 YAML 解析

ExportConfiguration configuration = new Yaml(new Constructor(ExportConfiguration.class))
    .loadAs(fileString, ExportConfiguration.class);

這次我們有一個文檔必須共同響應 ExportConfiguration class。

注 1:配置文件 rest 的結構甚至內容完全沒有作用。 這是主要思想,在單個文件中獲取獨立配置

注 2:配置的 rest 可能是 JSON 或 XML 或其他。 我們有一個方法預處理器,它返回一個字符串配置——下一個處理器會正確解析它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM