Mise à jour 02/05/2018 (environ 4 ans plus tard) ... Je l'ai testé à nouveau car les gens ont voté jusqu'à ma question/réponse et Sotirios Delimanolis a raison de dire que je n'aurais pas à écrire le code dans ma réponse faire ce travail. J'ai utilisé essentiellement la même configuration de service RestTemplate/REST que celle illustrée dans ma question, le service REST ayant un type de contenu de réponse confirmé application/json et RestTemplate a pu traiter la réponse sans aucun problème dans une mappe.
J'appelle un service de repos qui renvoie JSON
comme ceci:
{
"some.key" : "some value",
"another.key" : "another value"
}
J'aimerais penser que je peux invoquer ce service avec un Java.util.Map
comme type de réponse, mais cela ne fonctionne pas pour moi. Je reçois cette exception:
org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [interface Java.util.Map]
Devrais-je simplement spécifier String
comme type de réponse et convertir JSON
en Map
?
Éditer je
Voici mon appel restTemplate:
private Map<String, String> getBuildInfo(String buildUrl) {
return restTemplate.getForObject(buildUrl, Map.class);
}
Voici comment je configure le restTemplate:
@PostConstruct
public void initialize() {
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
interceptors.add(new ClientHttpRequestInterceptor() {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
HttpRequestWrapper requestWrapper = new HttpRequestWrapper(request);
requestWrapper.getHeaders().setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
return execution.execute(requestWrapper, body);
}
});
restTemplate.setInterceptors(interceptors);
}
Edit II
Message d'erreur complet:
org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [interface Java.util.Map] and content type [application/octet-stream]
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.Java:108) ~[spring-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.Java:549) ~[spring-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.web.client.RestTemplate.execute(RestTemplate.Java:502) ~[spring-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.Java:239) ~[spring-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at idexx.ordering.services.AwsServersServiceImpl.getBuildInfo(AwsServersServiceImpl.Java:96) ~[classes/:na]
Comme je l'avais déjà noté, votre message d'erreur nous indique que vous recevez application/octet-stream
en tant que Content-Type
.
org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [interface Java.util.Map] and content type [application/octet-stream]
En tant que tel, le MappingJackson2HttpMessageConverter
de Jackson ne peut pas analyser le contenu (il attend le application/json
).
Réponse originale:
En supposant que le Content-Type
de votre réponse HTTP soit application/json
et que vous ayez Jackson 1 ou 2 sur le chemin de classe, un RestTemplate
peut désérialiser JSON comme vous le faites dans un Java.util.Map
parfaitement.
Avec l'erreur que vous obtenez et que vous n'avez pas affichée en entier, soit vous avez enregistré des objets HttpMessageConverter
personnalisés qui écrasent ceux par défaut, soit vous n'avez pas Jackson dans votre chemin de classe et le MappingJackson2HttpMessageConverter
n'est pas enregistré (ce qui désérialisation) ou vous ne recevez pas application/json
.
RestTemplate a une méthode appelée exchange qui prend une instance de ParameterizedTypeReference en tant que paramètre.
Pour faire une demande GET qui retourne un Java.util.Map
, créez simplement une instance d'une classe anonyme qui hérite de ParameterizedTypeReference.
ParameterizedTypeReference<HashMap<String, String>> responseType =
new ParameterizedTypeReference<HashMap<String, String>>() {};
Vous pouvez ensuite invoquer la méthode d'échange:
RequestEntity<Void> request = RequestEntity.get(URI("http://example.com/foo"))
.accept(MediaType.APPLICATION_JSON).build()
Map<String, String> jsonDictionary = restTemplate.exchange(request, responseType)
Mise à jour 02/05/2018 (environ 4 ans plus tard) ... Je l'ai testé à nouveau car les gens ont voté jusqu'à ma question/réponse et Sotirios Delimanolis a raison de dire que je n'aurais pas à écrire le code dans ma réponse faire ce travail. J'ai utilisé essentiellement la même configuration de service RestTemplate/REST que celle illustrée dans ma question, le service REST ayant un type de contenu de réponse confirmé application/json et RestTemplate a pu traiter la réponse sans aucun problème dans une mappe.
J'ai fini par obtenir le contenu en tant que String
et ensuite en le convertissant en Map
comme ceci:
String json = restTemplate.getForObject(buildUrl, String.class);
Map<String,String> map = new HashMap<String,String>();
ObjectMapper mapper = new ObjectMapper();
try {
//convert JSON string to Map
map = mapper.readValue(json, new TypeReference<HashMap<String,String>>(){});
} catch (Exception e) {
logger.info("Exception converting {} to map", json, e);
}
return map;
Je pense que vous pouvez atteindre votre objectif simplement en utilisant RestTemplate et en spécifiant un JsonNode comme type de réponse.
ResponseEntity<JsonNode> response =
restTemplate.exchange(url, HttpMethod.GET, entity, JsonNode.class);
JsonNode map = response.getBody();
String someValue = map.get("someValue").asText();
Je connais son ancien code, mais uniquement pour les autres personnes pouvant consulter cette rubrique: Si vous souhaitez enregistrer des convertisseurs supplémentaires avec RestTemplateBuilder, vous devez également enregistrer explicitement les convertisseurs par défaut.
@Bean
public RestTemplateBuilder builder() {
return new RestTemplateBuilder()
.defaultMessageConverters()
.additionalMessageConverters(halMessageConverter());
}
private HttpMessageConverter halMessageConverter() {
ObjectMapper objectMapper = new ObjectMapper().registerModule(new Jackson2HalModule());
TypeConstrainedMappingJackson2HttpMessageConverter halConverter = new TypeConstrainedMappingJackson2HttpMessageConverter(ResourceSupport.class);
halConverter.setSupportedMediaTypes(Collections.singletonList(MediaTypes.HAL_JSON));
halConverter.setObjectMapper(objectMapper);
return halConverter;
}