如何将DefaultMutableTreeNode(Java)序列化为JSON?

问题描述 投票:0回答:2

如何将树(使用DefaultMutableTreeNode类在Java中实现)序列化为JSON(通过RESTful方法传输到iOS客户端)?

我试过了:

String jsonString = (new Gson()).toJson(topNode);
// topNode is DefaultMutableTreeNode at the root

它与StackOverflowError坠毁。

java json serialization gson jtree
2个回答
2
投票

Swing的DefaultMutableTreeNode类是一个树状的数据结构,它包含childrenparent这种相同类型的实例。这就是为什么Gson的默认序列化器遇到无限递归,因此扔了一个StackOverflowError

要解决这个问题,你需要使用一个更智能的Gson来定制你的JsonSerializer,这个DefaultMutableTreeNode专门用于将JsonDeserializer转换为JSON。作为奖励,你可能还想提供一个DefaultMutableTreeNode来将这样的JSON转换回Gson

为此,创建你的new Gson()实例不仅仅是由Gson gson = new GsonBuilder() .registerTypeAdapter(DefaultMutableTreeNode.class, new DefaultMutableTreeNodeSerializer()) .registerTypeAdapter(DefaultMutableTreeNode.class, new DefaultMutableTreeNodeDeserializer()) .setPrettyPrinting() .create(); ,而是由

DefaultMutableTreeNodeSerializer

下面的DefaultMutableTreeNode负责将allowsChildren转换为JSON。它将其属性userObjectchildrenparent转换为JSON。请注意,它不会将public class DefaultMutableTreeNodeSerializer implements JsonSerializer<DefaultMutableTreeNode> { @Override public JsonElement serialize(DefaultMutableTreeNode src, Type typeOfSrc, JsonSerializationContext context) { JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("allowsChildren", src.getAllowsChildren()); jsonObject.add("userObject", context.serialize(src.getUserObject())); if (src.getChildCount() > 0) { jsonObject.add("children", context.serialize(Collections.list(src.children()))); } return jsonObject; } } 属性转换为JSON,因为这样做会再次产生无限递归。

JTree

为了进行测试,让我们将样本tree的根节点序列化为JSON,然后再次反序列化。

JTree tree = new JTree(); // create a sample tree Object topNode = tree.getModel().getRoot(); // a DefaultMutableTreeNode String jsonString = gson.toJson(topNode); System.out.println(jsonString); DefaultMutableTreeNode topNode2 = gson.fromJson(jsonString, DefaultMutableTreeNode.class);

{
  "allowsChildren": true,
  "userObject": "JTree",
  "children": [
    {
      "allowsChildren": true,
      "userObject": "colors",
      "children": [
        {
          "allowsChildren": true,
          "userObject": "blue"
        },
        {
          "allowsChildren": true,
          "userObject": "violet"
        },
        {
          "allowsChildren": true,
          "userObject": "red"
        },
        {
          "allowsChildren": true,
          "userObject": "yellow"
        }
      ]
    },
    {
      "allowsChildren": true,
      "userObject": "sports",
      "children": [
        {
          "allowsChildren": true,
          "userObject": "basketball"
        },
        {
          "allowsChildren": true,
          "userObject": "soccer"
        },
        {
          "allowsChildren": true,
          "userObject": "football"
        },
        {
          "allowsChildren": true,
          "userObject": "hockey"
        }
      ]
    },
    {
      "allowsChildren": true,
      "userObject": "food",
      "children": [
        {
          "allowsChildren": true,
          "userObject": "hot dogs"
        },
        {
          "allowsChildren": true,
          "userObject": "pizza"
        },
        {
          "allowsChildren": true,
          "userObject": "ravioli"
        },
        {
          "allowsChildren": true,
          "userObject": "bananas"
        }
      ]
    }
  ]
}

它生成以下JSON输出:

DefaultMutableTreeNodeDeserializer

下面的DefaultMutableTreeNode负责将JSON转换回How to serialize/deserialize a DefaultMutableTreeNode with Jackson?

它使用与DefaultMutableTreeNode的解串器相同的想法。 POJO不是很像POJO,因此与Gson不能很好地协同工作。因此,它使用了一个表现良好的allowsChildren辅助类(具有属性userObjectchildrenPOJO),并允许Gson将JSON内容反序列化为此类。然后POJO对象(及其DefaultMutableTreeNode儿童)被转换为DefaultMutableTreeNode对象(与public class DefaultMutableTreeNodeDeserializer implements JsonDeserializer<DefaultMutableTreeNode> { @Override public DefaultMutableTreeNode deserialize(JsonElement json, Type type, JsonDeserializationContext context) { return context.<POJO>deserialize(json, POJO.class).toDefaultMutableTreeNode(); } private static class POJO { private boolean allowsChildren; private Object userObject; private List<POJO> children; // no need for: POJO parent public DefaultMutableTreeNode toDefaultMutableTreeNode() { DefaultMutableTreeNode node = new DefaultMutableTreeNode(); node.setAllowsChildren(allowsChildren); node.setUserObject(userObject); if (children != null) { for (POJO child : children) { node.add(child.toDefaultMutableTreeNode()); // recursion! // this did also set the parent of the child-node } } return node; } // Following setters needed by Gson's deserialization: public void setAllowsChildren(boolean allowsChildren) { this.allowsChildren = allowsChildren; } public void setUserObject(Object userObject) { this.userObject = userObject; } public void setChildren(List<POJO> children) { this.children = children; } } } 儿童)。

JsonSerializer

0
投票

这是我的旧答案的改进替代品,它使用JsonDeserializerDefaultMutableTreeNodeTypeAdapter实现。这两个接口的API文档说:

新的应用程序应该更喜欢TypeAdapter,它的流API比这个接口的树API更有效。

因此,让我们使用这种首选方法并为DefaultMutableTreeNode实现Gson

要使用它,你可以像这样创建你的new Gson()实例(而不是仅使用Gson gson = new GsonBuilder() .registerTypeAdapterFactory(DefaultMutableTreeNodeTypeAdapter.FACTORY) .setPrettyPrinting() .create(); ):

DefaultMutableTreeNodeTypeAdapter

下面的DefaultMutableTreeNode负责将allowsChildren转换为JSON和从JSON转换。它写/读它的属性userObjectchildrenparent。不需要编写public class DefaultMutableTreeNodeTypeAdapter extends TypeAdapter<DefaultMutableTreeNode> { public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() { @Override @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { if (type.getRawType() == DefaultMutableTreeNode.class) { return (TypeAdapter<T>) new DefaultMutableTreeNodeTypeAdapter(gson); } return null; } }; private final Gson gson; private DefaultMutableTreeNodeTypeAdapter(Gson gson) { this.gson = gson; } @Override public void write(JsonWriter out, DefaultMutableTreeNode node) throws IOException { out.beginObject(); out.name("allowsChildren"); out.value(node.getAllowsChildren()); out.name("userObject"); gson.toJson(node.getUserObject(), Object.class, out); if (node.getChildCount() > 0) { out.name("children"); gson.toJson(Collections.list(node.children()), List.class, out); // recursion! } // No need to write node.getParent(), it would lead to infinite recursion. out.endObject(); } @Override public DefaultMutableTreeNode read(JsonReader in) throws IOException { in.beginObject(); DefaultMutableTreeNode node = new DefaultMutableTreeNode(); while (in.hasNext()) { switch (in.nextName()) { case "allowsChildren": node.setAllowsChildren(in.nextBoolean()); break; case "userObject": node.setUserObject(gson.fromJson(in, Object.class)); break; case "children": in.beginArray(); while (in.hasNext()) { node.add(read(in)); // recursion! // this did also set the parent of the child-node } in.endArray(); break; default: in.skipValue(); break; } } in.endObject(); return node; } } 属性,因为父子关系已经在JSON输出的嵌套结构中编码。

qazxswpoi
© www.soinside.com 2019 - 2024. All rights reserved.