Как сериализовать / десериализовать DefaultMutableTreeNode с Джексоном? - PullRequest
0 голосов
/ 06 марта 2019

Как мы можем сериализовать / десериализовать Swing DefaultMutableTreeNode в / из JSON с Джексоном?

Есть связанный вопрос Как сериализовать DefaultMutableTreeNode (Java) в JSON? . Но он попросил Gson, а не Джексон (и только для сериализации, а не для десериализации).

Для DefaultMutableTreeNode Джексона по умолчанию сериализация / сериализация не работает по разным причинам:

  • Содержит дочерние объекты, которые снова являются DefaultMutableTreeNode объектами. Но он не имеет канонических методов получения и установки для этого (например, getChildren() и setChildren(...)).
  • Содержит обратные ссылки (через методы getParent(), getRoot(), getPath()), что привело бы к бесконечной рекурсии и StackOverflow во время сериализации.
  • Он имеет много избыточных методов получения (например, isLeaf(), getNextSibling(), getLastChild(), ...) которые не нужны быть сериализованным, потому что они являются производными от других свойств.

1 Ответ

0 голосов
/ 07 марта 2019

Вы можете настроить Джексона ObjectMapper с JsonSerializer и JsonDeserializer специально созданный для преобразования DefaultMutableTreeNode в JSON и наоборот.

ObjectMapper objectMapper = new ObjectMapper()
    .registerModule(new SimpleModule()
        .addSerializer(DefaultMutableTreeNode.class, new DefaultMutableTreeNodeSerializer())
        .addDeserializer(DefaultMutableTreeNode.class, new DefaultMutableTreeNodeDeserializer()))
    .enable(SerializationFeature.INDENT_OUTPUT);

Ответственность за DefaultMutableTreeNodeSerializer ниже для преобразования DefaultMutableTreeNode в JSON. Это пишет allowsChildren, userObject и children DefaultMutableTreeNode в JSON. Это не пишет его parent, потому что это было бы привести к бесконечной рекурсии и StackOverflowError. Вместо этого родительские и дочерние отношения кодируются во вложенных структура JSON-вывода.

public class DefaultMutableTreeNodeSerializer extends JsonSerializer<DefaultMutableTreeNode> {

    @Override
    public void serialize(DefaultMutableTreeNode node, JsonGenerator gen, SerializerProvider serializers)
            throws IOException {
        gen.writeStartObject();
        gen.writeBooleanField("allowsChildren", node.getAllowsChildren());
        gen.writeObjectField("userObject", node.getUserObject());
        if (node.getChildCount() > 0)
            gen.writeObjectField("children", Collections.list(node.children()));
        // Don't write node.getParent(), it would lead to infinite recursion.
        gen.writeEndObject();
    }
}

Для тестирования вы можете сериализовать корневой узел образца JTree, и затем снова десериализовать его.

tree

JTree tree = new JTree(); // a sample tree
Object root = tree.getModel().getRoot(); // a DefaultMutableTreeNode
String json = objectMapper.writeValueAsString(root);
System.out.println(json);
DefaultMutableTreeNode root2 = objectMapper.readValue(json, DefaultMutableTreeNode.class);

Создает следующий вывод JSON:

{
  "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"
    } ]
  } ]
}

DefaultMutableTreeNodeDeserializer ниже отвечает за преобразование JSON обратно в DefaultMutableTreeNode.

DefaultMutableTreeNode очень не похож на POJO и поэтому не очень хорошо работает вместе с Джексоном. Поэтому я создал класс помощника POJO с хорошим поведением (со свойствами allowsChildren, userObject и children) и пусть Джексон десериализует контент JSON в этот класс. Затем я конвертирую POJO объект (и его POJO дети) к DefaultMutableTreeNode объекту (с DefaultMutableTreeNode детьми).

public class DefaultMutableTreeNodeDeserializer extends JsonDeserializer<DefaultMutableTreeNode> {

    @Override
    public DefaultMutableTreeNode deserialize(JsonParser parser, DeserializationContext context)
            throws IOException {
        return parser.readValueAs(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 Jackson'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;
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...