在没有方括号和字段名称的情况下使用 Jackson 将 Tree 转换为 Json

Converting Tree to Json using Jackson without having square braces and field names

我在 Java 中有以下树结构(-> 表示父级)

节点 A -> 节点 B

节点 B -> 节点 C

节点 C -> 节点 D

节点 C -> 节点 E

我有以下class代表树


    class TreeNode{
       private String name;
       private List<TreeNode> children;
    }

现在,当我将数据序列化为 Json 时,我希望得到以下输出。


    {
      "A": {
        "B": {
          "C": {
            "D": {},
            "E": {}
          }
        }
      }
    }

我已经设法使用自定义序列化程序来删除字段名称,但是,我收到的当前响应有方括号,我不确定如何删除它们。

我得到的当前输出


     {
      "A": [
        {
          "B": [
            {
              "C": [
                {
                  "D": []
                },
                {
                  "E": []
                }
              ]
            }
          ]
        }
      ]
    }

我实现的序列化器

class TreeNodeSerializer extends JsonSerializer<TreeNode> {
        @Override
        public void serialize(Sample2Test.TreeNode value,
                              JsonGenerator gen,
                              SerializerProvider serializers) throws IOException, JsonProcessingException {
            gen.writeStartObject();
            gen.writeObjectField(value.getName(), value.getChildren());
            gen.writeEndObject();
        }
    }

JSON(又名 JavaScript)中的方括号表示列表(又名数组)。

您没有提供序列化程序的代码,但我猜您只是添加 children - 这是一个 List.

而不是 List,您应该放置 Map,其中键是 children 的名称,值是 children 的 children .当然,这只有在您的名字是唯一的情况下才有效。

核心问题就在这里

gen.writeObjectField(value.getName(), value.getChildren());

value.getChildren() 是一个 List<Node>。所以,序列化器将它序列化为一个数组,然后返回自定义序列化器TreeNodeSerializer序列化每个children.

不太明白你是怎么得到的

            {
              "D": [],
              "E": []
            }

因为你只写了一个键给object,所以我预计它应该是

            {
              "D": []
            },
            {
              "E": []
            }

相反。

要解决这个问题,您还需要实际序列化 children:

gen.writeFieldName(value.getName());
gen.writeStartObject();
for (Node child: value.getChildren()) {
    gen.writeObjectField(child.getName(), child);
}
gen.writeEndObject();

但是,您现在可以看到 child 的名称出现了两次,一次是在 parent 序列化中,一次是在它自己的序列化中。

因此,您可以将它从自身中移除,但是您还需要解决根节点的问题,这意味着您需要类似包含节点 A 的根节点之类的东西。

这是有道理的,因为现在没有什么能阻止您的根 object 拥有多个密钥,除非您的结构不允许这样做。

所以,最终的方法应该是:

gen.writeStartObject();
for (Node child: value.getChildren()) {
    gen.writeObjectField(child.getName(), child);
}
gen.writeEndObject();

并创建一个虚拟根节点来保存您的实际根节点