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