あなたにとって最良の選択肢はJackson Streaming APIだと思います。これにより、オブジェクト グラフをテラバースしながら POJO を json にシリアライズできるため、シリアライズ プロセスの制御を維持し、循環参照やその他の特殊なケースを検出して処理できます。
編集:循環参照を処理する例を実装しようとしましたが、完了できませんでした。ここに私の中間結果があります:
- デフォルトを呼び出す
ObjectMapper.WriteValue(...)
と、次の例外が発生しますcom.fasterxml.jackson.databind.JsonMappingException: Direct self-reference leading to cycle
。これは、Jackson が自己参照のケースを検出できることを意味します。デフォルトのデリアライザーは、このケースを処理する方法を知りません。
- 例外をスローするデフォルトの動作は、これがいつ設定されるかを指定することでオフにできます
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"}}