Java对象序列化和转换为JSON

Java object serialization and conversion to JSON

本文关键字:JSON 转换 对象 序列化 Java      更新时间:2023-09-26

我有一个Java对象。它有许多字段,这些字段引用其他不同类型的Java对象,有时引用本身。该对象可以最好地描述为具有双向引用(或循环)的映射(或图形)。我无权分析它的结构,但为了解决问题,我必须序列化这个图并将其存储在JSON String中。

事实上,我不能真正看到对象的结构,使用库类是我唯一的选择(据我所知)。我试过json-io, json-lib,谷歌genson, gson和flexjson。但是所有这些库要么被卡住,抛出一个异常,因为存在一个循环,或者能够返回一个json(只有json-io这样做),但有很多重要的字段被跳过(那些是惰性加载的,需要getter)。

问题:在测试上面列出的库只是为了解决我的问题时,是否存在一些我可能遗漏的东西?

我的Java对象确实很复杂,但我不希望它像facebook这样的大型网站使用的对象那样复杂。有哪些关键库及其特定配置可用于解决我的问题?

我认为你最好的选择是Jackson Streaming API。它允许您在遍历对象图时将POJO序列化为json,从而保持对序列化过程的控制,并且您可以检测和处理循环引用和任何其他特殊情况。

编辑:我试图实现一个例子,处理循环引用,但我不能完成它。以下是我的中间发现:

  1. 调用默认的ObjectMapper.WriteValue(...)会导致以下异常com.fasterxml.jackson.databind.JsonMappingException: Direct self-reference leading to cycle,这意味着Jackson可以检测到自引用的情况。默认派生程序不知道如何处理这种情况。
  2. 默认抛出异常的行为可以通过指定mapper.configure(SerializationFeature.FAIL_ON_SELF_REFERENCES, false);来关闭,默认派生程序将导致堆栈溢出。因此,我们需要实现一个自定义序列化器来检测和处理自引用。
  3. 我试着写一个自定义序列化器,做以下事情:A)检测自我引用。B)如果找到了,打印一些东西来标记参考文献。C)如果没有,则执行默认的序列化。然而,我不知道如何调用"默认序列化"。我的中间解决方案如下:

一个可以有self引用的示例类:

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"}}