WildFly 26 升级后 Jackson 自定义序列化(如 @JsonValue、@JsonSerialize)失效,根本原因是类路径中存在冲突的 Jackson 版本(尤其是认证模块自带的 2.13.x),覆盖了 WildFly 内置的 RESTEasy-Jackson2 提供器;通过统一依赖管理并启用 Jackson 优先策略即可彻底解决。
wildfly 26 升级后 jackson 自定义序列化(如 `@jsonvalue`、`@jsonserialize`)失效,根本原因是类路径中存在冲突的 jackson 版本(尤其是认证模块自带的 2.13.x),覆盖了 wildfly 内置的 resteasy-jackson2 提供器;通过统一依赖管理并启用 jackson 优先策略即可彻底解决。
在将 Java EE 应用从 WildFly 23 迁移至 WildFly 26 的过程中,开发者常遇到 Jackson 序列化行为异常的问题:@JsonValue 注解被忽略、自定义 JsonSerializer 未触发、@JsonFormat 对日期失效等。这些现象看似是 Jackson 配置问题,实则源于 WildFly 模块类加载机制引发的 依赖版本冲突——尤其当项目或自定义安全模块(如 Elytron 登录模块)显式打包了独立的 Jackson JAR(如 jackson-databind-2.13.4.2.jar)时,会绕过 WildFly 官方推荐的 resteasy-jackson2-provider,导致 Jackson 的注解处理器和序列化链无法正常注册。
? 根本原因分析
WildFly 26 默认使用 RESTEasy 6.x + Jackson 2.13+ 组合,并通过模块系统(org.jboss.resteasy.resteasy-jackson2-provider)提供标准化的 JSON 处理能力。但若应用或其依赖模块(如自定义 login-module)在 module.xml 中直接引入了 jackson-* JAR 文件,JVM 将优先加载这些“本地”版本,从而:
- 覆盖 WildFly 内置的 ObjectMapper 实例;
- 使 @JsonValue、@JsonSerialize(using = ...) 等注解在 RESTEasy 的消息体写入阶段被跳过;
- 导致 ResponseListWrapper 返回 { "objects": [...] } 而非期望的 [...],且 JacksonListSerializer.serialize() 方法永不执行。
⚠️ 注意:Maven 中声明
provided 的 Jackson 依赖(如 jackson-databind-2.12.7.1)不会影响运行时——WildFly 忽略 WAR 内的 provided 依赖,完全由服务器模块决定实际使用的 Jackson 版本。
✅ 正确解决方案
1. 清理冲突的 Jackson 模块依赖
检查所有自定义模块(尤其是安全相关模块)的 module.xml,移除所有显式的 jackson-core、jackson-databind、jackson-annotations JAR 声明。例如:
<!-- ❌ 错误:手动引入 Jackson JAR(导致版本冲突) --> <resources><resource-root path="jackson-databind-2.13.4.2.jar"></resource-root><resource-root path="jackson-core-2.13.4.jar"></resource-root><resource-root path="jackson-annotations-2.13.4.jar"></resource-root></resources>
替换为标准 WildFly 模块依赖:
<!-- ✅ 正确:委托给 WildFly 内置的 Jackson 提供器 --> <dependencies><module name="org.jboss.resteasy.resteasy-jaxrs"></module><module name="org.jboss.resteasy.resteasy-jackson2-provider"></module></dependencies>
2. 强制 RESTEasy 使用 Jackson(而非默认 Json-B)
WildFly 26 默认启用 Jakarta JSON Binding(Json-B)作为首选 JSON 处理器。需在启动参数中显式启用 Jackson 优先策略:
# 启动 WildFly 时添加 JVM 参数 -D"resteasy.preferJacksonOverJsonB"="true"
? 提示:该参数可添加到 standalone.conf(Linux)或 standalone.conf.bat(Windows)中,或通过管理控制台配置。
3. 验证 jboss-deployment-structure.xml 配置
确保应用的 WEB-INF/jboss-deployment-structure.xml 不屏蔽 Jackson 提供器,且正确声明依赖:
<jboss-deployment-structure><deployment><dependencies><!-- 必须包含,否则 Jackson 提供器不可见 --><module name="org.jboss.resteasy.resteasy-jackson2-provider"></module><!-- 其他必要模块(如安全、JAX-RS) --><module name="org.wildfly.security.elytron"></module><module name="org.jboss.resteasy.resteasy-jaxrs"></module></dependencies></deployment></jboss-deployment-structure>
4. (可选)显式注册 Jackson 提供器(增强兼容性)
若仍存在不确定性,可在 web.xml 中显式声明 RESTEasy 的 Jackson 提供器:
<context-param><param-name>resteasy.providers</param-name><param-value>org.jboss.resteasy.plugins.providers.jackson.ResteasyJackson2Provider</param-value></context-param>
✅ 效果验证
完成上述修改并重启 WildFly 后,原示例接口 /json 将正确返回:
[
{ "a": "a1", "b": "b1" },
{ "a": "a2", "c": "c2" }
]
同时,@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 等日期格式注解也将生效,@JsonValue 方法被准确调用,自定义 JacksonListSerializer 的 serialize() 方法会在响应生成时执行。
? 总结与最佳实践
| 事项 | 推荐做法 |
|---|---|
| Jackson 版本管理 | 完全交由 WildFly 模块控制,禁止在 module.xml 或 WAR 中打包 Jackson JAR |
| 依赖声明方式 | 使用 |
| JSON 处理器选择 | 生产环境必须设置 -Dresteasy.preferJacksonOverJsonB=true |
| Maven 依赖作用域 | jackson-* 依赖保持 |
| 调试技巧 | 启用 RESTEasy 日志:logging.category."org.jboss.resteasy".level=DEBUG,观察 MessageBodyWriter 选择过程 |
遵循此方案,不仅能修复 @JsonValue 和 @JsonSerialize 失效问题,还可避免 WildFly 26+ 中因 Json-B 与 Jackson 混用导致的序列化歧义、@JsonInclude 不生效、泛型类型擦除异常等连锁问题。










