解决hutoolJSON,报错Type definition error: [simple type, class cn.hutool.json.JSONNull],一文全部搞懂

该文章已生成可运行项目,

❌ 错误核心信息

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 ​​默认不认识 HutoolJSONNull 类​​,因此无法将其序列化为 JSON,导致抛出了 InvalidDefinitionException

具体来说(以我的项目代码来举例):

  • 我的 Result 对象中的 data 字段是一个 List
  • 这个 List 中的某个元素是一个 cn.hutool.json.JSONObject
  • 这个 JSONObject 中有一个字段 firmwareId 的值是 JSONNull(可能是数据库查询结果为 NULL,Hutool 将其转成了 JSONNull);
  • Jackson 在序列化时发现 JSONNull 没有对应的序列化器,于是报错。

✅ 解决方案

有几种方式可以解决这个问题(当然也可以直接换用json,避免使用hutool的json,已知换成fastjson或者Jackson都可以,就不需要其它处理了)


方案 1:避免在返回给前端的对象中使用 HutoolJSONObjectJSONNull

​推荐做法​​:将 HutoolJSONObject 转换为标准的 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(个人推荐

如果​​必须​​在返回结果中使用 HutoolJSONObject,可以为 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 格式不符合预期,甚至隐藏其他潜在问题。因此​​不推荐​​此方式。


📌 总结

方案描述推荐度
方案 1Hutool JSONObject 转为标准 Java 对象(如 Map 或 DTO)⭐⭐⭐⭐⭐
方案 2自定义 Jackson 序列化器支持 JSONNull⭐⭐⭐⭐⭐
方案 3禁用 FAIL_ON_EMPTY_BEANS(治标不治本)

当然方案1最好,比较标准,但是我选方案2比较简洁省事

本文章已经生成可运行项目
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值