Search code examples
javayamldeserializationsnakeyaml

Parse a single POJO from multiple YAML documents representing different classes


I want to use a single YAML file which contains several different objects - for different applications. 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 totally unknown to the application working with MyClass1. The file is always a valid YAML, of course.

The YAML may be of any structure we need to implement such a multi-class container. The preferred parsing tool is snakeyaml.

Is it sensible? How can I ignore all but one object?

UPD: replaced all "document" with "object". I think we have to speak about the single YAML document containing several objects of different structure. More of it, the parser knows exactly only 1 structure and wants to ignore the rest.

UDP2: I think it is impossible with snakeyaml. We have to read all objects anyway - and select the needed one later. But maybe I'm wrong.

UPD2: sample config file

--- 
- 
  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

Solution

  • The answer of @flyx was very helpful for me, opening the way to workaround the library (in our case - snakeyaml) limitations by overriding some methods. Thanks a lot! It's quite possible there is a final solution in it - but not now. Besides, the simple solution below is robust and should be considered even if we'd found the complete library-intruding solution.

    I've decided to solve the task by double distilling, sorry, processing the configuration file. Imagine the latter consisting of several parts and every part is marked by the unique token-delimiter. For the sake of keeping the YAML-likenes, it may be

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

    The first pass is pre-processing. For the given String fileString and String key (and DELIMITER = "\n---\n". for example) we select a substring with the key-defined configuration:

    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);                                   
    } 
    

    Now we feed the fileString to the simple YAML parsing

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

    This time we have a single document that must co-respond to the ExportConfiguration class.

    Note 1: The structure and even the very content of the rest of configuration file plays absolutely no role. This was the main idea, to get independent configurations in a single file

    Note 2: the rest of configurations may be JSON or XML or whatever. We have a method-preprocessor that returns a String configuration - and the next processor parses it properly.