0

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

事实上,我无法真正了解对象的结构,使用库类是我唯一的选择(据我所知)。我尝试过 json-io、json-lib、google genson、gson 和 flexjson。但是所有这些库要么因为循环的存在而卡住并抛出异常,要么能够返回一个 json(只有 json-io 这样做)但是跳过了很多重要的字段(那些是延迟加载的) ,并且需要吸气剂)。

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

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

4

1 回答 1

0

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

编辑:我试图实现一个处理循环引用的示例,但我无法完成它。这是我的中间发现:

  1. 调用默认值ObjectMapper.WriteValue(...)会导致以下异常com.fasterxml.jackson.databind.JsonMappingException: Direct self-reference leading to cycle,这意味着杰克逊可以检测到自引用的情况。默认的 deializer 不知道如何处理这种情况。
  2. mapper.configure(SerializationFeature.FAIL_ON_SELF_REFERENCES, false);可以通过指定何时设置来关闭默认的抛出异常行为,默认的反序列化器会导致堆栈溢出。所以我们需要实现一个自定义的序列化器来检测和处理自引用。
  3. 我试图编写一个自定义序列化程序,它执行以下操作: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"}}

于 2015-06-07T06:46:28.283 回答