使用上下文堆栈而不是使用JsonIdentityInfo或JsonBackReference&处理Jackson循环依赖项。 JsonManagedReference

时间:2015-05-04 00:59:01

标签: json serialization jackson circular-dependency circular-reference

我使用Jackson来序列化JSON,但我的JSON客户端不是Java,也不使用Jackson。

我想避免循环引用序列化无限递归,每当序列化整个bean会导致无限递归时,序列化bean的id而不是整个bean。

这可以通过维护当前序列化上下文的堆栈来实现。

每当Jackson开始序列化bean时,它应该看看堆栈是否包含bean。

如果bean已经在堆栈中,则序列化id而不是整个bean,从而避免无限递归。

如果bean不在堆栈中,则将其推入堆栈,并正常序列化整个bean。

杰克逊完成序列化bean后,将bean从堆栈中弹出。

因此,我希望以下Java序列化为以下JSON:

爪哇:

class A {
    String id;
    B      b;
    B      c;
}

class B {
    String id;
    A      a;
}

class Main {
    public static void main(String[] args) {
        A a = new A();
        B b = new B();
        a.id = "a1";
        b.id = "b1";
        a.b = b;
        a.c = b;
        b.a = a;
        ObjectMapper m = new ObjectMapper();
        System.out.println(m.writeValueAsString(a));
        System.out.println(m.writeValueAsString(b));
    }
}

JSON:

{
    "id": "a1",
    "b": {
        "id": "b1",
        "a":  "a1"
    },
    "c": {
        "id": "b1",
        "a":  "a1"
    }
}

{
    "id": "b1",
    "a": {
        "id": "a1",
        "b":  "b1"
    }
}

我只知道两种内置的Jackson处理循环引用的方法,如果我理解正确的话,它们都不能输出上面的JSON:

  1. @JsonIdentityInfo,在最佳设置时,注释A& B with:

    @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
    

    将输出(带有指示问题的注释):

    {
        "id": "a1",
        "b": {
            "id": "b1",
            "a":  "a1"
        },
        "c": "b1" // problem: value of "c" is b.id instead of b with b.a = a.id
    }
    
    {
        "id": "b1",
        "a": {
            "id": "a1",
            "b":  "b1"
        }
    }
    
  2. @JsonManagedReference& @JsonBackReference,我必须指定一方为前方,另一方为后方。假设我选择A - > B属性作为前进,然后我得到:

    {
        "id": "a1",
        "b": {
            "id": "b1",
            "a":  "a1"
        },
        "c": {
            "id": "b1",
            "a":  "a1"
        }
    }
    
    {
        "id": "b1"
        // problem: "a" isn't serialized
    }
    
  3. 是否有任何内置的杰克逊方式按照我的要求进行序列化?

    如果没有,杰克逊是否会保留序列化堆栈?

    如果是这样,我该如何访问它,并以某种方式修改序列化输出?

    如果没有,我如何挂钩杰克逊来维护我自己的类中的堆栈,这些类实现了一些Jackson接口/扩展了一些Jackson类,然后使用该堆栈来影响序列化?

1 个答案:

答案 0 :(得分:1)

杰克逊确实保留了几个筹码。较旧的版本处于JsonGenerator级别,请参阅getOuputContext()。这可以让你看到物理输出的内容,即哪个范围(对象,数组)是开放的。

但Jackson 2.5添加了新的方法JsonGenerator.getCurrentValue(),以及来自数据绑定的匹配调用,它还应该为您提供序列化的对象图形视图,至少在组合两者时。 要访问当前值的祖先,您需要遍历"输出上下文",向输出堆栈请求当前值。