【问题标题】:Why do i get an stackoverflow error when using jackson even though using @JsonIgnoreProperties为什么即使使用 @JsonIgnoreProperties 在使用 jackson 时也会出现 stackoverflow 错误
【发布时间】:2019-07-27 06:20:21
【问题描述】:

我正在尝试将带有 jackson 的 DefaultMutableTreeNode 对象序列化为 json 字符串。因此我需要使用一个混合抽象类,它是 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 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

【问题讨论】:

  • 您能在此处添加堆栈跟踪吗?
  • 现在将其添加到问题摘要中
  • 与其写一个mix-in,我认为写一个JsonSerializer for DefaultMutableTreeNode会容易得多。

标签: java jackson stack-overflow mixins self-reference


【解决方案1】:

当您开始遍历他们的 getters 方法时,此类会生成循环。要打破它们,您需要使用 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 方法是创建新的POJO,它代表您的树已准备好进行序列化并且没有循环。

【讨论】:

    【解决方案2】:

    正如杰克逊的文档中所述:https://fasterxml.github.io/jackson-annotations/javadoc/2.6/com/fasterxml/jackson/annotation/JsonProperty.html

    公共@interface JsonProperty

    可用于将非静态方法定义为 逻辑属性的“setter”或“getter”(取决于它的 签名),或要使用的非静态对象字段(序列化, 反序列化)作为逻辑属性。

    我确实认为您注释的方法不是属性的 setter 或 getter。

    例如:

    @JsonProperty("previousNode")
        abstract DefaultMutableTreeNode getPreviousNode();
    

    此方法似乎没有获取属性,而是在计算一个节点。尝试删除方法上的所有注释,看看是否能解决问题。

    【讨论】:

    猜你喜欢
    • 2020-12-15
    • 2015-03-08
    • 2021-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-01
    • 2016-08-13
    • 2021-06-26
    相关资源
    最近更新 更多