I'm building a REST API with Spring; well currently I'm failing to do so.
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
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;
}
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.
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());
}
}
Apparently there is no default JSON Converter to I needed to create a little Configuration class:
@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
var jsonConverter = new MappingJackson2HttpMessageConverter();
var objectMapper = new ObjectMapper();
jsonConverter.setObjectMapper(objectMapper);
return jsonConverter;
}