Spring Boot使用Jackson时引入含Gson的胖Jar导致反序列化异常如何解决
可行性结论
完全可行,只要解决第三方胖Jar对项目原有Jackson依赖的干扰问题即可。
问题根因
你遇到的泛型识别失效、反序列化出LinkedHashMap的问题,本质是第三方胖Jar干扰了Jackson核心类的加载/配置逻辑,大概率是以下几种情况:
- 胖Jar中打包了篡改过的或者版本不兼容的Jackson核心类(
jackson-databind、jackson-core),类加载时优先加载了胖Jar中的类,导致TypeFactory的泛型解析逻辑被篡改 - 胖Jar通过SPI机制注册了自定义的Jackson Module,替换/修改了默认
TypeFactory的实现逻辑 - Spring Boot Devtools的
RestartClassLoader加载顺序异常,导致泛型类型信息读取错误(你的异常栈已明确出现Devtools类加载器)
排查步骤
- 验证Jackson核心类来源:在IDE中查找
com.fasterxml.jackson.databind.type.TypeFactory、com.fasterxml.jackson.core.type.TypeReference两个类,确认加载的Jar包是否为Spring Boot 2.4.5官方匹配的Jackson 2.11.x版本,而非第三方胖Jar提供 - 检查SPI配置:查看类路径下
META-INF/services/com.fasterxml.jackson.databind.Module文件,是否存在第三方胖Jar注册的自定义Jackson模块 - 排查Devtools冲突:临时禁用Spring Boot Devtools启动项目,验证问题是否复现
解决方案
按优先级从高到低尝试:
方案1:修正TypeReference写法(成本最低)
不要在TypeReference中使用菱形运算符,显式声明泛型类型,避免运行时泛型信息丢失:
// 错误写法:泛型推断可能在类加载逻辑受干扰时失效 // List<Book> books = objectMapper.readValue(getReader("books.json"), new TypeReference<>() {}); // 正确写法:显式指定泛型 List<Book> books = objectMapper.readValue(getReader("books.json"), new TypeReference<List<Book>>() {});
方案2:修复Devtools类加载冲突
如果禁用Devtools后问题消失,在application.properties中添加配置,将第三方胖Jar排除在重启类加载范围外即可:
spring.devtools.restart.additional-exclude=libs/你的第三方Jar包名.jar
方案3:强制指定Jackson依赖优先级,避免被胖Jar覆盖
在build.gradle中添加强制版本配置,确保官方Jackson依赖优先加载:
configurations.all { resolutionStrategy { // 强制使用Spring Boot 2.4.5匹配的Jackson版本 force 'com.fasterxml.jackson.core:jackson-core:2.11.4', 'com.fasterxml.jackson.core:jackson-databind:2.11.4', 'com.fasterxml.jackson.core:jackson-annotations:2.11.4', 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.11.4', 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.4' } }
方案4:显式指定ObjectMapper的TypeFactory实现
构造ObjectMapper时直接传入官方默认的TypeFactory,避免被第三方模块篡改:
private static ObjectMapper getMapper() { // 显式使用官方默认TypeFactory,不受外部自定义实现影响 TypeFactory defaultTypeFactory = TypeFactory.defaultInstance(); ObjectMapper mapper = new ObjectMapper(null, null, defaultTypeFactory); mapper.registerModule(new Jdk8Module()); mapper.registerModule(new JavaTimeModule()); return mapper; }
方案5:重打包第三方胖Jar做依赖隔离(最彻底)
如果以上方案都无效,使用Shadow插件对第三方胖Jar进行重打包,将其包含的Jackson、Gson等公共依赖做包名重定向(relocate),彻底隔离依赖冲突:
- 单独创建一个空的Gradle项目,引入Shadow插件
- 引入第三方胖Jar作为依赖
- 配置relocate规则,将
com.fasterxml.jackson.**、com.google.gson.**等公共包重定向到自定义包路径下 - 打包后使用重打包后的Jar替代原有胖Jar引入项目
内容的提问来源于stack exchange,提问作者Febell
相关产品推荐
相关产品推荐

