
❌ 错误核心信息
org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class cn.hutool.json.JSONNull]
...
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class cn.hutool.json.JSONNull
错误原因分析
使用 Jackson 作为 JSON 序列化工具(Spring Boot 默认使用 Jackson),而返回对象中包含了 cn.hutool.json.JSONNull 类型的值。Jackson 默认不认识 Hutool 的 JSONNull 类,因此无法将其序列化为 JSON,导致抛出了 InvalidDefinitionException。
具体来说(以我的项目代码来举例):
- 我的
Result对象中的data字段是一个List; - 这个
List中的某个元素是一个cn.hutool.json.JSONObject; - 这个
JSONObject中有一个字段firmwareId的值是JSONNull(可能是数据库查询结果为NULL,Hutool 将其转成了JSONNull); - Jackson 在序列化时发现
JSONNull没有对应的序列化器,于是报错。
✅ 解决方案
有几种方式可以解决这个问题(当然也可以直接换用json,避免使用hutool的json,已知换成fastjson或者Jackson都可以,就不需要其它处理了):
方案 1:避免在返回给前端的对象中使用 Hutool 的 JSONObject 或 JSONNull
推荐做法:将 Hutool 的 JSONObject 转换为标准的 Java 对象(如 Map 或自定义的 DTO 类),这样 Jackson 就能正常序列化了。
例如:
// 原始代码可能类似这样:
JSONObject jsonObj = ...; // Hutool 的 JSONObject
result.setData(Collections.singletonList(jsonObj));
// 应改为:
Map<String, Object> map = new HashMap<>();
jsonObj.forEach((k, v) -> {
if (v instanceof JSONNull) {
map.put(k, null); // 将 JSONNull 转为 Java 的 null
} else {
map.put(k, v);
}
});
result.setData(Collections.singletonList(map));
这样转换后,Jackson 就能正确处理 null 值了。
方案 2:自定义 Jackson 的序列化器,支持 JSONNull(个人推荐)
如果必须在返回结果中使用 Hutool 的 JSONObject,可以为 JSONNull 编写一个自定义的 Jackson 序列化器。
示例:
public class JSONNullSerializer extends JsonSerializer<JSONNull> {
@Override
public void serialize(JSONNull value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeNull(); // 将 JSONNull 序列化为 JSON 的 null
}
}
然后注册这个序列化器:
@Configuration
public class JacksonConfig {
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(JSONNull.class, new JsonNullSerializer());
mapper.registerModule(module);
return mapper;
}
这样 Jackson 就知道如何处理 JSONNull 了,会将其序列化为 null。
⚠️ 注意:这种方式虽然能解决问题,但会让你的代码和 Hutool 耦合更紧密,不利于后续替换 JSON 库。如果可以,推荐方案 1。
一般方案二解决是最简单的,当然序列化器也可以自定义这个写
@Configuration
public class JacksonConfig {
@Bean
public MappingJackson2HttpMessageConverter jackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(JSONNull.class, new JsonNullSerializer());
mapper.registerModule(module);
converter.setObjectMapper(mapper);
return converter;
}
如果问题还没有解决和之前一样的报错,那就只有一个原因,你配置的这里没有生效注入,最大的可能性是你系统原本就已经有一个地方自定义这个序列化器了,所以你只需要全局搜索一下SimpleModule
把simpleModule.addSerializer(JSONNull.class, new JsonNullSerializer());手动加到系统原本的自定义json序列化方法中,这样就不需要自己再去重新注册这个序列化器了

方案 3:禁用 FAIL_ON_EMPTY_BEANS(不推荐)
我的日志中提到:
(to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
可以通过配置 Jackson 禁用这个特性:
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
return mapper;
}
但这只是“绕过”问题,并不会真正解决 JSONNull 无法序列化的问题,可能最终返回的 JSON 格式不符合预期,甚至隐藏其他潜在问题。因此不推荐此方式。
📌 总结
| 方案 | 描述 | 推荐度 |
|---|---|---|
| 方案 1 | 将 Hutool JSONObject 转为标准 Java 对象(如 Map 或 DTO) | ⭐⭐⭐⭐⭐ |
| 方案 2 | 自定义 Jackson 序列化器支持 JSONNull | ⭐⭐⭐⭐⭐ |
| 方案 3 | 禁用 FAIL_ON_EMPTY_BEANS(治标不治本) | ⭐ |
当然方案1最好,比较标准,但是我选方案2比较简洁省事

1238

被折叠的 条评论
为什么被折叠?



