Search code examples
javasnakeyaml

Java SnakeYaml - prevent dumping reference names


I have the following method which I use to get the object converted to yaml representation (which I can eg. print to console)

@Nonnull
private String outputObject(@Nonnull final ObjectToPrint packageSchedule) {
    DumperOptions options = new DumperOptions();
    options.setAllowReadOnlyProperties(true);
    options.setPrettyFlow(true);
    return new Yaml(new Constructor(), new JodaTimeRepresenter(), options).dump(ObjectToPrint);
}

All is good, but for some object contained within ObjectToPrint structure I get something like reference name and not the real object content, eg.

!!com.blah.blah.ObjectToPrint
businessYears:
- businessYearMonths: 12
  ppiYear: &id001 {
    endDate: 30-06-2013,
    endYear: 2013,
    startDate: 01-07-2012,
    startYear: 2012
  }
  ppiPeriod:
    ppiYear: *id001
    endDate: 27-03-2014
    startDate: 21-06-2013
    units: 24.000
  number: 1

As you can see from the example above I have ppiYear object printed (marked as $id001) and the same object is used in ppiPeriod but only the reference name is printed there, not the object content. How to print the object content everytime I use that object within my structure, which I want to be converted to yaml (ObjectToPrint). PS. It would be nice not to print the reference name at all (&id001) but thats not crucial


Solution

  • This is because you reference the same object at different places. To avoid this you need to create copies of those objects. Yaml does not have a flag to switch this off, because you might get into endless loops in case of cyclic references. However you might tweak Yaml source code to ignore double references:

    look at Serializer line ~170 method serializeNode:

    ...
     if ( this.serializedNodes.contains(node) ) {
        this.emmitter.emit( new AliasEvent( ... ) );
     } else {
        serializedNodes.add(node); // <== Replace with myHook(serializedNodes,node);
     ...
    
     void myHook(serializedNodes,node) {
        if ( node's class != myClass(es) to avoid ) {
            serializedNodes.add(node);
        }
    

    if you find a way to avoid Yaml to put nodes into the serializedNodes collection, your problem will be solved, however your programm will loop endless in case of cyclic references.

    Best solution is to add a hook which avoids registering only the class you want to be written plain.