17

假设我有一个用 Java 实现的参数化树,如下所示:

public class Tree<E> {
   private static class Node {
      E element;
      List<Node> children.
   }

   Node root;

   //... You get the idea.
}

这里的想法是,上面的实现只关心树的拓扑结构,而不知道将通过实例化存储在树中的元素的任何信息。

现在,假设我希望我的树元素是地理。它们按树组织的原因是因为大陆包含国家,国家包含州或省,等等。为简单起见,地理具有名称和类型:

public class GeoElement { String name; String type; }

所以,最后,地理层次结构看起来像这样:

public class Geography extends Tree<GeoElement> {}

现在到杰克逊连载。假设 Jackson 序列化器可以看到字段,则此实现的直接序列化将如下所示:

{
   "root": {
      "element": {
         "name":"Latin America",
         "type":"Continent"
      }
      "children": [
          {
             "element": {
                "name":"Brazil",
                "type":"Country"
             },
             "children": [
                 // ... A list of states in Brazil
             ]
          },
          {
             "element": {
                "name":"Argentina",
                "type":"Country"
             },
             "children": [
                 // ... A list of states in Argentina
             ]
          }
      ]
   }

这种 JSON 渲染不好,因为它包含来自 Tree 和 Node 类的不必要的工件,即“根”和“元素”。我需要的是这个:

{
   "name":"Latin America",
   "type":"Continent"
   "children": [
       {
          "name":"Brazil",
          "type":"Country"
          "children": [
             // ... A list of states in Brazil
          ]
       },
       {
          "name":"Argentina",
          "type":"Country"
          "children": [
             // ... A list of states in Argentina
          ]
       }
   ]
}

非常感谢任何帮助。-伊戈尔。

4

4 回答 4

9

你需要的是@JsonUnwrapped.

用于指示属性应该被序列化“解包”的注解;也就是说,如果它将被序列化为 JSON 对象,则其属性将作为其包含对象的属性包含在内

将此注解添加到类rootTree&element字段中Node,如下所示:

public class Tree<E> {
   private static class Node {

      @JsonUnwrapped
      E element;
      List<Node> children.
   }

   @JsonUnwrapped
   Node root;

   //... You get the idea.
}

它会给你你想要的输出:

{
    "name": "Latin America",
    "type": "Continent",
    "children": [{
        "name": "Brazil",
        "type": "Country",
        "children": []
    }, {
        "name": "Argentina",
        "type": "Country",
        "children": []
    }]
}
于 2018-07-28T14:11:59.313 回答
5

也许@JsonValue像这样使用:

public class Tree<E> {
  @JsonValue
  Node root;
}

如果你只需要“打开”你的树?

于 2013-01-29T05:53:13.137 回答
0

您最好的选择是为您的对象构建和注册自定义序列化程序。

定义你的序列化器:

public class NodeSerializer extends StdSerializer<Node> {

然后在您的 Node 类上:

@JsonSerialize(using = NodeSerializer.class)
public class Node {
}

并且在里面NodeSerializer

@Override
    public void serialize(
      Node node, JsonGenerator jgen, SerializerProvider provider) 
      throws IOException, JsonProcessingException {

        jgen.writeStartObject();
        jgen.writeStringField("name", node.element.name);

        jgen.writeStringField("type", node.element.type);
        //Process children
        serializeFields(node, jgen, provider);
        jgen.writeEndObject();
    }

这个通用框架将让您控制元素如何序列化。您可能还需要对象内部的对象,@JsonIgnore因为您的自定义序列化程序负责将该信息推送到生成的 JSON 中。网上有很多关于自定义序列化程序和覆盖默认 JSON 导出的内容。elementNode

您可以使用 Tree 实现的序列化程序以类似的方式摆脱 root。

如果您不想在类上注册序列化程序,您也可以使用以下方法一次一个地进行ObjectMapper

ObjectMapper mapper = new ObjectMapper();

SimpleModule module = new SimpleModule();
module.addSerializer(Node.class, new NodeSerializer());
mapper.registerModule(module);

String serialized = mapper.writeValueAsString(tree);

注释方法将在全球范围内应用。这种方法允许对自定义序列化程序的使用方式/位置进行一些控制。

于 2018-07-28T10:14:24.027 回答
-2

对于删除element类型,一种可能性是更改您的结构,以便名称和类型将直接包含在每个节点中:

public class TreeGeo {
   private static class Node {
      String name;
      String type;
      List<Node> children.
   }

   Node root;
}

对于删除root类型,我不知道。我想你可以从 jsonObject 中提取一个子对象,但我对 Jackson 了解不多。但是,您可以给它一个更好的名称,例如world或操作生成的字符串以通过一些字符串操作手动删除它。

于 2013-01-29T09:41:09.310 回答