Spring RestTemplate 映射 JSON 对 Map 的响应抛出 MismatchedInputException
Spring RestTemplate Mapping JSON response to Map throws MismatchedInputException
我正在尝试将 JSON 从 Github 的提交详细信息 API 解析为 HashMap。我在测试中使用的示例 Json 是 here
测试代码为
@SpringJUnitConfig(classes = {GithubApiService.class, RestTemplateConfiguration.class})
@EnableAutoConfiguration
public class GithubApiServiceTest {
@Test
public void testGithubResponseJsonToMapConversion(
@Autowired RestTemplate restTemplate,
@Autowired GithubApiService service,
@Value("classpath:github/commit-payload.json") Resource commitPayloadFile) throws IOException {
final String COMMITS_URL = "https://api.github.com/repos/Codertocat/Hello-World/commits/sha";
//Stub response from Github Server
String responseJson = new ObjectMapper().writeValueAsString(
new String(Files.readAllBytes(Paths.get(commitPayloadFile.getFile().getAbsolutePath()))));
MockRestServiceServer mockGithubServer = MockRestServiceServer.createServer(restTemplate);
mockGithubServer.expect(requestTo(COMMITS_URL))
.andRespond(withSuccess().contentType(APPLICATION_JSON).body(responseJson));
//Call API Service
Map<String, Object> result = service.getCommitDetails(COMMITS_URL);
//Expect return type is hashmap
assertThat(result.get("sha")).isEqualTo("6dcb09b5b57875f334f61aebed695e2e4193db5e");
}
}
服务代码是
@Service
@AllArgsConstructor(onConstructor = @__(@Autowired))
public class GithubApiService {
@Autowired
private final RestTemplate restTemplate;
public Map<String, Object> getCommitDetails(String commitsUrl) {
ParameterizedTypeReference<Map<String, Object>> responseType = new ParameterizedTypeReference<Map<String, Object>>() {
};
RequestEntity<Void> request = RequestEntity.get(URI.create(commitsUrl)).accept(APPLICATION_JSON).build();
return restTemplate.exchange(request, responseType).getBody();
}
}
将 JSON
响应转换为 Map
失败并出现以下错误 (full log here)
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `java.util.LinkedHashMap` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{
"url": "https://api.github.com/repos/octocat/Hello-World/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e",
"sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e",
"node_id": "MDY6Q29tbWl0NmRjYjA5YjViNTc4NzVmMzM0ZjYxYWViZWQ2OTVlMmU0MTkzZGI1ZQ==",
"html_url": "https://github.com/octocat/Hello-World/commit/6dcb09b5b57875f334f61aebed695e2e4193db5e",
"comments_url": "https://api.github.com/repos/octocat/Hello-World/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e/comments",
因为我使用的是 spring-boot-starter-web
它会自动连接转换器,包括 MappingJackson2HttpMessageConverter
但调试器显示响应正在由 ByteArrayHttpMessageConverter
处理,尽管将内容类型设置为 application/json
.
糟糕,我应该使用 @EnableAutoConfiguration
的 @RestClientTest
注释来解决问题。
@EnableAutoConfiguration
是一个更通用的注释,它没有实现 @RestClientTest
所做的所有自动配置
我正在尝试将 JSON 从 Github 的提交详细信息 API 解析为 HashMap。我在测试中使用的示例 Json 是 here
测试代码为
@SpringJUnitConfig(classes = {GithubApiService.class, RestTemplateConfiguration.class})
@EnableAutoConfiguration
public class GithubApiServiceTest {
@Test
public void testGithubResponseJsonToMapConversion(
@Autowired RestTemplate restTemplate,
@Autowired GithubApiService service,
@Value("classpath:github/commit-payload.json") Resource commitPayloadFile) throws IOException {
final String COMMITS_URL = "https://api.github.com/repos/Codertocat/Hello-World/commits/sha";
//Stub response from Github Server
String responseJson = new ObjectMapper().writeValueAsString(
new String(Files.readAllBytes(Paths.get(commitPayloadFile.getFile().getAbsolutePath()))));
MockRestServiceServer mockGithubServer = MockRestServiceServer.createServer(restTemplate);
mockGithubServer.expect(requestTo(COMMITS_URL))
.andRespond(withSuccess().contentType(APPLICATION_JSON).body(responseJson));
//Call API Service
Map<String, Object> result = service.getCommitDetails(COMMITS_URL);
//Expect return type is hashmap
assertThat(result.get("sha")).isEqualTo("6dcb09b5b57875f334f61aebed695e2e4193db5e");
}
}
服务代码是
@Service
@AllArgsConstructor(onConstructor = @__(@Autowired))
public class GithubApiService {
@Autowired
private final RestTemplate restTemplate;
public Map<String, Object> getCommitDetails(String commitsUrl) {
ParameterizedTypeReference<Map<String, Object>> responseType = new ParameterizedTypeReference<Map<String, Object>>() {
};
RequestEntity<Void> request = RequestEntity.get(URI.create(commitsUrl)).accept(APPLICATION_JSON).build();
return restTemplate.exchange(request, responseType).getBody();
}
}
将 JSON
响应转换为 Map
失败并出现以下错误 (full log here)
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `java.util.LinkedHashMap` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{
"url": "https://api.github.com/repos/octocat/Hello-World/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e",
"sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e",
"node_id": "MDY6Q29tbWl0NmRjYjA5YjViNTc4NzVmMzM0ZjYxYWViZWQ2OTVlMmU0MTkzZGI1ZQ==",
"html_url": "https://github.com/octocat/Hello-World/commit/6dcb09b5b57875f334f61aebed695e2e4193db5e",
"comments_url": "https://api.github.com/repos/octocat/Hello-World/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e/comments",
因为我使用的是 spring-boot-starter-web
它会自动连接转换器,包括 MappingJackson2HttpMessageConverter
但调试器显示响应正在由 ByteArrayHttpMessageConverter
处理,尽管将内容类型设置为 application/json
.
糟糕,我应该使用 @EnableAutoConfiguration
的 @RestClientTest
注释来解决问题。
@EnableAutoConfiguration
是一个更通用的注释,它没有实现 @RestClientTest
所做的所有自动配置