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用法)
- 给模型类添加
@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; }
- 测试类中注入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
相关产品推荐
相关产品推荐

