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

Spring REST API解析JSON RequestBody报错:类型ID/根名称不匹配

Spring REST API JSON解析错误解决

问题概述

调用接口时遇到两种JSON解析错误:
错误1:

JSON parse error: Could not resolve type id 'test1' as a subtype of crm.zappes.core.template.domain.model.TemplateRequest: known type ids = [TemplateRequest]

错误2:

JSON parse error: Root name ('test1') does not match expected ('TemplateRequest') for type crm.zappes.core.template.domain.model.TemplateRequest

模型类与JSON表现

给TemplateRequest添加@JsonTypeInfo注解后,序列化生成带根对象的JSON,触发错误1:

{"TemplateRequest":{"test1":"Anakin","test2":"Skywalker"}}

移除该注解后,生成扁平JSON,触发错误2:

{"test1":"Anakin","test2":"Skywalker"}

模型类代码:

@Data @Builder @NoArgsConstructor @AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
// 加此注解触发错误1,不加触发错误2
@JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME)
public class TemplateRequest {
    private String test1;
    private String test2;
}

控制器代码

接口端点期望接收JSON并转换为TemplateRequest对象,改为String类型时能正常接收,说明映射正常但解析失败:

@RestController
@RequestMapping("/zappes/")
public class TemplateController {
    @PostMapping(value = "/template/test", consumes = {MediaType.APPLICATION_JSON_VALUE})
    public ResponseEntity<String> testPost(@RequestBody TemplateRequest request) {
        return ResponseEntity.ok("Hello World");
    }
}

测试代码

发送请求的集成测试代码:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
class TemplateControllerIntegrationTests {
    @Test
    void testPost() {
        HttpHeaders headers = new HttpHeaders();
        headers.setBasicAuth("server_user", "server_password");

        var request = TemplateRequest.builder().test1("Anakin").test2("Skywalker").build();

        var requestEntity = new HttpEntity<>(request, headers);

        var restTemplate = new RestTemplate();
        var result = restTemplate.exchange("http://localhost:8083/zappes/template/test", HttpMethod.POST, requestEntity, String.class);

        Assertions.assertEquals("Hallo Welt", result.getBody());
    }
}

解决方案

方案1:保留根包裹格式(修复@JsonTypeInfo用法)

  1. 给模型类添加@JsonTypeName显式指定类型名称,避免解析歧义:
@Data @Builder @NoArgsConstructor @AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME)
@JsonTypeName("TemplateRequest") // 显式声明类型名称
public class TemplateRequest {
    private String test1;
    private String test2;
}
  1. 测试类中注入Spring容器配置好的RestTemplate,而非手动new,确保使用统一的Jackson配置:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
class TemplateControllerIntegrationTests {
    @Autowired
    private RestTemplate restTemplate;

    @Test
    void testPost() {
        HttpHeaders headers = new HttpHeaders();
        headers.setBasicAuth("server_user", "server_password");

        var request = TemplateRequest.builder().test1("Anakin").test2("Skywalker").build();

        var requestEntity = new HttpEntity<>(request, headers);

        var result = restTemplate.exchange("http://localhost:8083/zappes/template/test", HttpMethod.POST, requestEntity, String.class);

        Assertions.assertEquals("Hello World", result.getBody()); // 修正断言内容与控制器返回一致
    }
}

方案2:统一使用扁平JSON或全局配置根包裹

如果不需要手动控制根包裹,可通过Spring配置全局启用Jackson的根包裹特性,无需添加@JsonTypeInfo:
在application.yml中添加配置:

spring:
  jackson:
    serialization:
      wrap-root-value: true
    deserialization:
      unwrap-root-value: true

该配置会自动对所有序列化/反序列化的JSON添加/解析根对象,保持前后端格式统一。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 06:05:19