使用Jackson反序列化含泛型Java类时遇栈溢出,如何解决?
Jackson递归泛型反序列化StackOverflowError问题解决
问题描述
使用Jackson将JSON反序列化为Java对象时,以下类结构在反序列化Menu类时触发StackOverflowError:
public class NavMenu { private final List<Menu> menus = new ArrayList<>(); } public class Menu implements ItemContainer<Menu> { private final List<Item<Menu>> items = new ArrayList<>(); } public class Item<P extends ItemContainer<P>> implements ItemContainer<Item<P>> { private final List<Item<Item<P>>> items = new ArrayList<>(); } public interface ItemContainer<T extends ItemContainer<T>> { void add(Item<T> item); List<Item<T>> getItems(); }
栈跟踪片段:
java.lang.StackOverflowError at com.fasterxml.jackson.databind.type.TypeBase.toCanonical(TypeBase.java:72) at com.fasterxml.jackson.databind.type.SimpleType.buildCanonicalName(SimpleType.java:236) ...
已通过自定义NavMenu反序列化器解决,但实现递归且难以维护,希望了解是否为Jackson Bug,以及无需自定义反序列化器的解决方法。
问题根源
这不是Jackson的Bug,而是泛型结构导致的无限递归类型解析:
Item<P>实现ItemContainer<Item<P>>,同时其items字段定义为List<Item<Item<P>>>- 这会让Jackson在解析类型时不断嵌套:
Item<Item<Item<...P...>>>,最终耗尽栈空间抛出异常。
无需自定义反序列化器的解决方案
1. 调整泛型结构(推荐)
修改Item类的泛型约束,终止类型的无限嵌套:
public class Item<P extends ItemContainer<P>> implements ItemContainer<P> { // 将items类型改为List<Item<P>>,避免嵌套递归 private final List<Item<P>> items = new ArrayList<>(); @Override public void add(Item<P> item) { items.add(item); } @Override public List<Item<P>> getItems() { return items; } }
调整后,类型解析会终止在Item<P>,不会产生无限递归。
2. 使用@JsonTypeInfo明确类型边界
若无法修改泛型结构,可通过@JsonTypeInfo注解为Jackson提供类型标识,避免无限解析:
import com.fasterxml.jackson.annotation.JsonTypeInfo; @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class") public interface ItemContainer<T extends ItemContainer<T>> { void add(Item<T> item); List<Item<T>> getItems(); }
该注解会在JSON中添加类全名作为类型标记,让Jackson能准确识别不同层级的递归类型。
3. 用@JsonIgnoreType忽略深层类型(谨慎使用)
如果不需要反序列化深层嵌套的Item实例,可在Item类上添加@JsonIgnoreType,但此方法会忽略所有Item类型的反序列化,仅适用于特定场景:
import com.fasterxml.jackson.annotation.JsonIgnoreType; @JsonIgnoreType public class Item<P extends ItemContainer<P>> implements ItemContainer<Item<P>> { // ... 原有代码 }
内容的提问来源于stack exchange,提问作者Gandora
相关产品推荐
相关产品推荐

