web-dev-qa-db-fra.com

resttemplate getForObject map 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'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]
14
Zack Macomber

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.

11

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)
9
JeremyW

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;
8
Zack Macomber

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();
1
riversidetraveler

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;
}
0
WrRaThY