Spring Boot MockMvc测试Gson反序列化报Expected BEGIN_OBJECT异常
报错核心原因是手动创建的原生Gson实例默认不支持JSR310规范的Java 8时间类型(如OffsetDateTime)反序列化。
生产环境、Postman调用能正常解析,是因为Spring Boot默认使用Jackson作为JSON解析框架,且自动加载了JavaTimeModule适配OffsetDateTime、LocalDateTime这类时间类型,可以直接将ISO格式的时间字符串转换为对应时间对象。但单元测试中你没有复用Spring已配置好的解析器,自己实例化的原生Gson遇到OffsetDateTime类型时,默认会期望对应值是嵌套对象结构(即解析到BEGIN_OBJECT标记),但实际拿到的是时间字符串,因此抛出该异常。
按以下步骤可快速定位问题:
- 打印
response.getContentAsString()的完整内容,确认无多余转义字符、前后缀、BOM头,排除MockMvc响应内容编码异常、被额外包装的问题 - 脱离MockMvc环境做最小复现:直接用
new Gson()解析你给出的示例JSON和ExampleResponse类,会稳定复现相同报错,排除MockMvc请求流程的干扰 - 对比生产与测试环境的解析逻辑差异:生产走Spring MVC内置的Jackson转换器,测试用了无额外配置的原生Gson,两边解析规则不一致
任选其一即可,优先选择和生产逻辑一致的方案:
方案1:复用Spring内置Jackson解析器(推荐)
不要手动创建Gson实例,直接注入Spring Boot自动配置好的ObjectMapper,该实例默认已完成OffsetDateTime类型适配,无需额外配置:
// 单元测试中注入Spring上下文管理的ObjectMapper @Autowired private ObjectMapper objectMapper; // 替换原有Gson解析逻辑 ExampleResponse exampleResponse = objectMapper.readValue( response.getContentAsString(), ExampleResponse.class );
方案2:给Gson注册时间类型适配器
如果确定要使用Gson做解析,需要在构建Gson实例时注册JSR310时间类型的适配模块:
// 构建带时间适配能力的Gson实例 Gson gson = new GsonBuilder() .registerTypeAdapter(OffsetDateTime.class, new OffsetDateTimeAdapter()) .create(); // 再执行解析即可正常转换 ExampleResponse exampleResponse = gson.fromJson(responseString, ExampleResponse.class);
使用该方案需要确认适配器的时间格式与接口返回的ISO 8601时间格式匹配,避免格式转换错误。
方案3:临时简化方案
如果仅为临时跑通单测,可暂时将ExampleResponse类中的birthDate、created字段类型改为String,拿到字符串值后再手动调用OffsetDateTime.parse()转换为时间对象。该方案与生产环境类定义不一致,不建议长期使用。
内容的提问来源于stack exchange,提问作者pixel

