Spring解析JSON请求正文:“无法解析类型ID”或“根名称与预期不匹配”

yftpprvb  于 2022-12-10  发布在  Spring
关注(0)|答案(1)|浏览(523)

I'm building a REST API with Spring; well currently I'm failing to do so.

TL;DR

I get either this (error 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]
or this (error 2)
JSON parse error: Root name ('test1') does not match expected ('TemplateRequest') for type crm.zappes.core.template.domain.model.TemplateRequest

Model

I used @JsonTypeInfo to wrap the class name around it; that leads to error 1.

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

If I use the default without this annotation the generated JSON doesn't have a wrapping root element which leads to error 2:

{"test1":"Anakin","test2":"Skywalker"}
@Data @Builder @NoArgsConstructor @AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
// With this I get error 1, without it error 2
@JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME)
public class TemplateRequest {
    private String test1;
    private String test2;
}

Controller

In this Controller Endpoint I want the JSON to be converted into a TemplateRequest Model Object.

@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");
    }
}

If I change it to @RequestBody String request it works fine and I see the 2 JSON variants (see above), so the endpoint mapping itself works. Spring just cannot parse the JSON into a model object. Which is kind of weird, because the JSON was also generated by the Spring REST framework. See next section.

Test

Here I'm sending the POST Call to the Controller.

@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());
    }
}
l0oc07j2

l0oc07j21#

显然没有默认的JSON转换器,我需要创建一个小的Configuration类:

@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
    var jsonConverter = new MappingJackson2HttpMessageConverter();
    var objectMapper = new ObjectMapper();
    jsonConverter.setObjectMapper(objectMapper);
    return jsonConverter;
}

相关问题