You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin Moshi适配器如何处理JsonDataException,类型不匹配时设为null

解决JSON类型不匹配解析异常的方案

针对老旧后端返回JSON类型不符(比如契约规定返回字符串却返回对象/空字符串)导致的JsonDataException Expected a string but was BEGIN_OBJECT异常,可通过以下方式将解析错误的字段设为null并忽略错误:

1. 全局配置(一次性解决所有字段)

如果用Jackson作为JSON解析框架,可通过全局配置关闭类型不匹配时的异常抛出,让框架自动将错误字段设为null:

ObjectMapper objectMapper = new ObjectMapper();
// 核心配置:遇到类型不匹配时不抛异常,直接设为null
objectMapper.configure(DeserializationFeature.FAIL_ON_INVALID_TYPE, false);
// 同时忽略未知字段(可选,避免后端新增字段导致解析失败)
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

如果是Spring Boot项目,也可以在配置文件中设置:

spring:
  jackson:
    deserialization:
      fail-on-invalid-type: false
      fail-on-unknown-properties: false
      accept-empty-string-as-null-object: true # 把空字符串转为null对象

这种方式最简单,所有类型不匹配的字段都会被自动设为null,无需修改实体类。

2. 单个字段精准处理(仅针对有问题的字段)

如果不想全局生效,只需要处理特定字段,可以给字段添加自定义反序列化器:
比如你的data字段本该是对象但可能返回空字符串,data2本该是字符串但可能返回对象,可这样写实体类和反序列化器:

// 响应实体类
public class ApiResponse {
    // 处理data字段:空字符串转null,类型不匹配也转null
    @JsonDeserialize(using = SafeObjectDeserializer.class)
    private Data data;

    private String other_data;

    // 处理data2字段:非字符串类型转null
    @JsonDeserialize(using = SafeStringDeserializer.class)
    private String data2;

    // getter、setter省略
}

// 安全对象反序列化器:处理空字符串/类型不匹配
class SafeObjectDeserializer extends StdDeserializer<Data> {
    public SafeObjectDeserializer() {
        super(Data.class);
    }

    @Override
    public Data deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        try {
            JsonToken token = p.currentToken();
            if (token == JsonToken.VALUE_STRING && p.getText().isEmpty()) {
                // 空字符串返回null
                return null;
            } else if (token == JsonToken.START_OBJECT) {
                // 正常解析对象
                return p.readValueAs(Data.class);
            } else {
                // 其他类型(比如数组、数字)跳过,返回null
                p.skipChildren();
                return null;
            }
        } catch (JsonDataException e) {
            // 捕获解析异常,跳过当前字段返回null
            p.skipChildren();
            return null;
        }
    }
}

// 安全字符串反序列化器:非字符串类型转null
class SafeStringDeserializer extends StdDeserializer<String> {
    public SafeStringDeserializer() {
        super(String.class);
    }

    @Override
    public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        try {
            if (p.currentToken() == JsonToken.VALUE_STRING) {
                return p.getText();
            } else {
                // 遇到非字符串类型(比如对象),跳过并返回null
                p.skipChildren();
                return null;
            }
        } catch (JsonDataException e) {
            p.skipChildren();
            return null;
        }
    }
}

这种方式更灵活,只对标记的字段生效,不影响其他正常字段。


疑问解答

是否需要在适配器中处理?

不是必须的。Jackson的全局配置或字段注解已经能在DTO解析阶段自动处理异常,不需要额外在适配器层写逻辑。如果你的架构中适配器负责数据转换兜底,也可以在这里捕获解析异常后手动设null,但这种方式不如框架自带的配置优雅高效。

是否必须手动解析全部JSON?

完全不需要。上面的方案都是基于Jackson的自动解析能力,只需要针对有问题的字段做特殊配置,其他字段正常自动解析即可。手动全解析不仅繁琐,还容易引入新的错误,优先用框架原生功能解决。

内容的提问来源于stack exchange,提问作者Unii

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 08:33:28