Java SnakeYaml-防止转储引用名称

Java SnakeYaml-防止转储引用名称,java,snakeyaml,Java,Snakeyaml,我使用以下方法将对象转换为yaml表示(例如打印到控制台) 一切都很好,但对于ObjectToPrint结构中包含的某些对象,我得到的是类似于引用名称的内容,而不是真正的对象内容,例如 !!com.blah.blah.ObjectToPrint businessYears: - businessYearMonths: 12 ppiYear: &id001 { endDate: 30-06-2013, endYear: 2013, startDate: 01-0

我使用以下方法将对象转换为
yaml
表示(例如打印到控制台)

一切都很好,但对于
ObjectToPrint
结构中包含的某些对象,我得到的是类似于引用名称的内容,而不是真正的对象内容,例如

!!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
从上面的示例中可以看到,我打印了
ppiYear
对象(标记为
$id001
),并且在
ppiPeriod
中使用了相同的对象,但只打印了引用名称,而不打印对象内容。 如何在每次使用结构中的对象时打印对象内容,我希望将其转换为yaml(
ObjectToPrint
)。
注:最好不要打印引用名称(
&id001
),但这并不重要,因为您在不同的位置引用同一对象。为了避免这种情况,您需要创建这些对象的副本。 Yaml没有关闭此功能的标志,因为在循环引用的情况下,您可能会进入无止境的循环。 但是,您可能会调整Yaml源代码以忽略双重引用:

查看序列化程序行~170方法序列化节点:

...
 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(this.serializedNodes.contains(node)){
this.emmitter.emit(新别名事件(…);
}否则{

serializedNodes.add(node);//为了在不更改SnakeYAML源代码的情况下执行此操作,您可以定义:

public class NonAnchorRepresenter extends Representer {

    public NonAnchorRepresenter() {
        this.multiRepresenters.put(Map.class, new RepresentMap() {
            public Node representData(Object data) {
                return representWithoutRecordingDescendents(data, super::representData);
            }            
        });
    }

    protected Node representWithoutRecordingDescendents(Object data, Function<Object,Node> worker) {
        Map<Object,Node> representedObjectsOnEntry = new LinkedHashMap<Object,Node>(representedObjects);
        try {
            return worker.apply(data);
        } finally {
            representedObjects.clear();
            representedObjects.putAll(representedObjectsOnEntry);
        }        
    }

}
public类非anchorrepresenter扩展Representer{
公共非AnchorRepresenter(){
this.multirepresents.put(Map.class,new-RepresentMap()){
公共节点representData(对象数据){
返回不带记录子代的representData(数据,super::representData);
}            
});
}
受保护的节点表示,不包含记录子代(对象数据、功能工作程序){
Map representedObjectsOnEntry=新的LinkedHashMap(representedObjects);
试一试{
返回工人。应用(数据);
}最后{
representedObjects.clear();
representedObjects.putAll(representedObjectsOnEntry);
}        
}
}
并将其用作例如
new Yaml(new SafeConstructor(),new NonAnchorRepresenter());

这只做映射,并且在必要时使用锚定,即映射引用祖先的位置。如果需要,它需要对集合和列表进行类似的扩展。(在我的例子中,最大的问题是空映射。)


(在SnakeYAML代码库中,基于
Representer.representData
查看一个选项,例如
setAllowAnchors
默认为true,如果不允许,上面的逻辑将在递归后重置
representedObjects
。我认为可能会出现无休止的循环,但这是错误的。)aightfroward使用此策略检测对父映射的任何引用并快速失败。)

我刚刚注释了if(this.serializedNodes.contains(node)){this.emitter.emit(new-AliasEvent(tAlias,null,null));}else{来自serializedNode方法和锚节点(node);来自serialize方法。这会阻止创建锚和别名。这是OP要求的:-)。您需要正确实现myHook,才能仅关闭某些类的引用检测。
public class NonAnchorRepresenter extends Representer {

    public NonAnchorRepresenter() {
        this.multiRepresenters.put(Map.class, new RepresentMap() {
            public Node representData(Object data) {
                return representWithoutRecordingDescendents(data, super::representData);
            }            
        });
    }

    protected Node representWithoutRecordingDescendents(Object data, Function<Object,Node> worker) {
        Map<Object,Node> representedObjectsOnEntry = new LinkedHashMap<Object,Node>(representedObjects);
        try {
            return worker.apply(data);
        } finally {
            representedObjects.clear();
            representedObjects.putAll(representedObjectsOnEntry);
        }        
    }

}