#java #jackson #stack-overflow #mixins #self-reference
#java #jackson #переполнение стека #смешивания #ссылка на себя
Вопрос:
Я пытаюсь сериализовать объект DefaultMutableTreeNode с помощью jackson в строку json. Поэтому мне нужно использовать абстрактный класс mix-in, который является своего рода прокси для класса DefaultMutableTreeNode по умолчанию. Вероятно, это связано с полями самоссылки, но я не могу их распознать.
Смешанный класс:
@JsonIgnoreProperties(ignoreUnknown = true)
public abstract class DefaultMutableTreeNodeMixIn {
@JsonCreator
public DefaultMutableTreeNodeMixIn(@JsonProperty Object userObject) {};
@JsonCreator
public DefaultMutableTreeNodeMixIn(@JsonProperty Object userObject,
@JsonProperty boolean allowsChildren) {};
@JsonProperty("childCount")
abstract int getChildCount();
@JsonProperty("depth")
abstract int getDepth();
@JsonProperty("firstChild")
abstract TreeNode getFirstChild();
@JsonProperty("firstLeaf")
abstract DefaultMutableTreeNode getFirstLeaf();
@JsonProperty("lastChild")
abstract TreeNode getLastChild();
@JsonProperty("lastLeaf")
abstract DefaultMutableTreeNode getLastLeaf();
@JsonProperty("leafCount")
abstract int getLeafCount();
@JsonProperty("level")
abstract int getLevel();
@JsonProperty("nextLeaf")
abstract DefaultMutableTreeNode getNextLeaf();
@JsonProperty("nextNode")
abstract DefaultMutableTreeNode getNextNode();
@JsonProperty("nextSibling")
abstract DefaultMutableTreeNode getNextSibling();
@JsonProperty("parent")
abstract TreeNode getParent();
@JsonProperty("path")
abstract TreeNode[] getPath();
@JsonProperty("previousLeaf")
abstract DefaultMutableTreeNode getPreviousLeaf();
@JsonProperty("previousNode")
abstract DefaultMutableTreeNode getPreviousNode();
@JsonProperty("previousSibling")
abstract DefaultMutableTreeNode getPreviousSibling();
@JsonProperty("siblingCount")
abstract int getSiblingCount();
@JsonProperty("isLeaf")
abstract boolean isLeaf();
@JsonProperty("isRoot")
abstract boolean isRoot();
}
ObjectMapper:
ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(DefaultMutableTreeNode.class,DefaultMutableTreeNodeMixIn.class);
String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(serverFileTree);
System.out.println(json);
(serverFileTree является объектом типа DefaultMutableTreeNode по умолчанию)
Трассировка ошибки:
at com.fasterxml.jackson.databind.ser.std.ObjectArraySerializer.serializeContents(ObjectArraySerializer.java:252)
at com.fasterxml.jackson.databind.ser.std.ObjectArraySerializer.serialize(ObjectArraySerializer.java:213)
at com.fasterxml.jackson.databind.ser.std.ObjectArraySerializer.serialize(ObjectArraySerializer.java:22)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155) [...]
Caused by: java.lang.StackOverflowError
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access$100(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:737)
... 1011 more
Комментарии:
1. не могли бы вы, пожалуйста, добавить сюда трассировку стека?
2. теперь добавил это в сводку проблем
3. Вместо того, чтобы писать mix-in, я думаю, было бы намного проще написать
JsonSerializer
forDefaultMutableTreeNode
.
Ответ №1:
Этот класс генерирует циклы, когда вы начинаете использовать их методы получения. Чтобы разбить их, вам нужно использовать JsonBackReference
аннотацию. Ваш mixin
может выглядеть следующим образом:
@JsonIgnoreProperties(ignoreUnknown = true)
abstract class DefaultMutableTreeNodeMixIn {
@JsonCreator
public DefaultMutableTreeNodeMixIn(@JsonProperty Object userObject) {
}
@JsonCreator
public DefaultMutableTreeNodeMixIn(@JsonProperty Object userObject, @JsonProperty boolean allowsChildren) {
}
@JsonProperty("childCount")
abstract int getChildCount();
@JsonProperty("depth")
abstract int getDepth();
@JsonProperty("firstChild")
@JsonBackReference
abstract TreeNode getFirstChild();
@JsonProperty("firstLeaf")
@JsonBackReference
abstract DefaultMutableTreeNode getFirstLeaf();
@JsonProperty("lastChild")
@JsonBackReference
abstract TreeNode getLastChild();
@JsonProperty("lastLeaf")
@JsonBackReference
abstract DefaultMutableTreeNode getLastLeaf();
@JsonProperty("leafCount")
abstract int getLeafCount();
@JsonProperty("level")
abstract int getLevel();
@JsonProperty("nextLeaf")
abstract DefaultMutableTreeNode getNextLeaf();
@JsonProperty("nextNode")
abstract DefaultMutableTreeNode getNextNode();
@JsonProperty("nextSibling")
abstract DefaultMutableTreeNode getNextSibling();
@JsonProperty("parent")
abstract TreeNode getParent();
@JsonProperty("path")
@JsonBackReference
abstract TreeNode[] getPath();
@JsonProperty("previousLeaf")
abstract DefaultMutableTreeNode getPreviousLeaf();
@JsonProperty("previousNode")
abstract DefaultMutableTreeNode getPreviousNode();
@JsonProperty("previousSibling")
abstract DefaultMutableTreeNode getPreviousSibling();
@JsonProperty("siblingCount")
abstract int getSiblingCount();
@JsonProperty("isLeaf")
abstract boolean isLeaf();
@JsonProperty("isRoot")
abstract boolean isRoot();
}
Но, вероятно, лучший OOP
способ — создать new POJO
, который представляет ваше дерево, готовое к сериализации и без циклов.
Ответ №2:
Как указано в документации Jackson: https://fasterxml.github.io/jackson-annotations/javadoc/2.6/com/fasterxml/jackson/annotation/JsonProperty.html
public @interface JsonProperty
Аннотация маркера, которая может использоваться для определения нестатического метода как «установщика» или «получателя» для логического свойства (в зависимости от его подписи), или нестатического поля объекта, которое будет использоваться (сериализовано, десериализовано) в качестве логического свойства.
Я действительно думаю, что вы указали методы, которые не являются установщиком или получателем свойств.
Например:
@JsonProperty("previousNode")
abstract DefaultMutableTreeNode getPreviousNode();
Похоже, что этот метод не не получает свойство, вместо этого он вычисляет узел. Попробуйте удалить все аннотации к методам, чтобы посмотреть, решит ли это проблему.
Комментарии:
1. «getPreviousNode(): возвращает узел, который предшествует этому узлу при обходе в предварительном порядке дерева этого узла.» ( docs.oracle.com/javase/8/docs/api/javax/swing/tree /… ) Я позаботился о том, чтобы все методы возвращали значения при их аннотировании