我认为对你来说最好的选择是Jackson Streaming API。它允许您在遍历对象图的同时将 POJO 转换为 json,从而保持对序列化过程的控制,并且您可以检测和处理循环引用和任何其他特殊情况。
编辑:我试图实现一个处理循环引用的示例,但我无法完成它。这是我的中间发现:
- 调用默认值
ObjectMapper.WriteValue(...)
会导致以下异常com.fasterxml.jackson.databind.JsonMappingException: Direct self-reference leading to cycle
,这意味着杰克逊可以检测到自引用的情况。默认的 deializer 不知道如何处理这种情况。
mapper.configure(SerializationFeature.FAIL_ON_SELF_REFERENCES, false);
可以通过指定何时设置来关闭默认的抛出异常行为,默认的反序列化器会导致堆栈溢出。所以我们需要实现一个自定义的序列化器来检测和处理自引用。
- 我试图编写一个自定义序列化程序,它执行以下操作:a)检测自引用。b) 如果找到,打印一些东西来标记参考。c) 如果没有,则进行默认序列化。但是,我看不到如何调用“默认序列化”。我的中间解决方案如下:
可以具有自引用的示例类:
public class Node {
public String name = "";
public Node child = null;
public Node(String name) { this.name = name; }
public String getname() { return name; }
public Node getChild() { return child; }
public void setChild(Node n) { child = n; }
}
自定义序列化程序
public class NodeJsonSerializer extends JsonSerializer<Node> {
// list so we can detect multiple cases of self references
static List<Node> alreadySerializedNodes = new ArrayList<>();
@Override
public void serialize(Node n, JsonGenerator gen, SerializerProvider serializers)
throws IOException, JsonProcessingException {
for (Node alreadySerialized : alreadySerializedNodes) {
// do not invoke equals() since you want to find duplicate references
if (alreadySerialized == n) {
// mark this as self reference
gen.writeStartObject();
gen.writeStringField("node-ref", alreadySerialized.getname());
gen.writeEndObject();
return;
}
}
alreadySerializedNodes.add(n);
// default derialization ...
gen.writeStartObject();
gen.writeStringField("name", n.getname());
gen.writeObjectField("child", n.getChild());
gen.writeEndObject();
}
}
来电:
Node n1 = new Node("n1");
n1.setChild(n1); // self referencing
ObjectMapper mapper = new ObjectMapper();
// registering custom serializer is through module
SimpleModule sm = new SimpleModule("MyModule");
sm.addSerializer(Node.class, new NodeJsonSerializer());
// making sure default serializer ignores self referencing is through module mapper.configure(SerializationFeature.FAIL_ON_SELF_REFERENCES, false);
mapper.registerModule(sm);
System.out.println(mapper.writeValueAsString(n1));
输出是{"name":"n1","child":{"node-ref":"n1"}}