web-dev-qa-db-fra.com

RestClientException: Impossible d'extraire la réponse. aucun convertisseur HttpMessageConverter approprié trouvé

En utilisant la commande curl:

curl -u 591bf65f50057469f10b5fd9:0cf17f9b03d056ds0e11e48497e506a2 https://backend.tdk.com/api/devicetypes/59147fd79e93s12e61499ffe/messages

Je reçois une réponse JSON:

{"data":[{"device":"18SE62","time":1494516023,"data":"3235","snr":"36.72",...

J'enregistre la réponse sur un fichier txt et l'analyse à l'aide de jackson, et tout va bien

ObjectMapper mapper = new ObjectMapper();
        File f = new File(getClass().getResource
                    ("/result.json").getFile());
        MessageList messageList = mapper.readValue(f, MessageList.class);

et je suppose que je devrais obtenir le même résultat en utilisant RestTemplate mais ce n'est pas le cas

RestTemplate restTemplate = new RestTemplate();
        MessageList messageList = 
                restTemplate.getForObject("http://592693f43c87815f9b8145e9:[email protected]/api/devicetypes/591570373c87894b4eece34d/messages", MessageList.class);

J'ai une erreur à la place

Exception in thread "main" org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class com.tdk.domain.backend.MessageList] and content type [text/html;charset=iso-8859-1]
    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.Java:109)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.Java:655)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.Java:613)
    at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.Java:287)
    at com.tdk.controllers.restful.client.RestTemplateExample.main(RestTemplateExample.Java:27)

J'ai essayé de définir le contentType:

HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);


        MessageList messageList = 
                restTemplate.getForObject(url, entity, MessageList.class);

mais alors j'ai eu une erreur de compilation

The method getForObject(String, Class<T>, Object...) in the type RestTemplate is not applicable for the arguments (String, HttpEntity<String>, 
 Class<MessageList>)

J'ai aussi essayé d'ajouter un convertisseur de Jackson Message

  List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();        
            //Add the Jackson Message converter
            messageConverters.add(new MappingJackson2HttpMessageConverter());    
            //Add the message converters to the restTemplate
            restTemplate.setMessageConverters(messageConverters); 

            MessageList messageList = 
                    restTemplate.getForObject(url, MessageList.class);

Mais alors j'ai eu cette erreur:

Exception in thread "main" org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class com.tdk.domain.backend.MessageList] and content type [text/html;charset=iso-8859-1]
    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.Java:109)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.Java:655)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.Java:613)
    at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.Java:287)
    at com.tdk.controllers.restful.client.RestTemplateExample.main(RestTemplateExample.Java:51)

J'ai aussi essayé d'ajouter la classe

@Configuration
@EnableWebMvc
public class MvcConf extends WebMvcConfigurationSupport {

    protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(converter());
        addDefaultHttpMessageConverters(converters);
    }

    @Bean
    MappingJackson2HttpMessageConverter converter() {

        MappingJackson2HttpMessageConverter converter 
                    = new MappingJackson2HttpMessageConverter();
        return converter;
    }

}

mais j'ai eu l'erreur:

org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class com.tdk.domain.backend.MessageList] and content type [text/html;charset=iso-8859-1]
    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.Java:109)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.Java:655)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.Java:613)
    at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.Java:287)
33

Le problème principal ici est type de contenu [text/html; charset = iso-8859-1] reçu du service, mais le type de contenu réel doit être application/json; charset = iso -8859-1

Afin de surmonter cela, vous pouvez introduire un convertisseur de messages personnalisé. et enregistrez-le pour tout type de réponse (c'est-à-dire ignorer l'en-tête du type de contenu de la réponse). Juste comme ça

List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();        
//Add the Jackson Message converter
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();

// Note: here we are making this converter to process any kind of response, 
// not only application/*json, which is the default behaviour
converter.setSupportedMediaTypes(Collections.singletonList(MediaType.ALL));        
messageConverters.add(converter);  
restTemplate.setMessageConverters(messageConverters); 
72
Ilya Dyoshin

J'avais un problème très similaire, et il s'est avéré être assez simple; mon client n'incluait pas de dépendance de Jackson, même si le code a été compilé correctement , mais les convertisseurs de magie automatique pour JSON n'étaient pas inclus. Voir cette solution liée à RestTemplate.

En bref, j'ai ajouté une dépendance de Jackson à mon pom.xml et cela a fonctionné:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.5.1</version>
</dependency>
23
gbonehead

Bien que la réponse acceptée résolve le problème initial du PO, je soupçonne que la plupart des gens qui trouvent cette question par le biais d'une recherche Google sont susceptibles (statistiquement parlant) de rencontrer un problème totalement différent qui se produit comme si le problème était identique pas de HttpMessageConverter approprié trouvé exception.

Sous les couvertures, MappingJackson2HttpMessageConverter avalera toutes les exceptions qui se produisent dans sa méthode canRead(), censée détecter automatiquement si la charge utile convient au décodage JSON. L'exception est remplacée par un simple retour booléen qui communique essentiellement désolé, je ne sais pas comment décoder ce message aux API de niveau supérieur (RestClient). Ce n'est qu'après que les méthodes canRead () de tous les autres convertisseurs ont renvoyé la valeur false, l'exception aucun HttpMessageConverter approprié n'a été trouvé est levée par l'API de niveau supérieur, occultant totalement le problème.

Pour les personnes qui n'ont pas trouvé la cause première (comme vous et moi, mais pas l'OP), le moyen de résoudre ce problème consiste à placer un point d'arrêt du débogueur sur onMappingJackson2HttpMessageConverter.canRead(), puis d'activer un point d'arrêt général sur toute exception, et cliquez sur Continuer. La prochaine exception est la vraie cause racine.

Mon erreur spécifique s'est avérée être qu'un des beans a référencé une interface qui manquait les annotations de désérialisation appropriées.

13
Alex R

Si la réponse ci-dessus de @ Ilya Dyoshin n'a pas encore été récupérée, essayez d'obtenir la réponse dans un objet String.

(Pour ma part, je pensais que l'erreur avait été résolue par le fragment de code d'Ilya, la réponse obtenue était un échec (erreur) du serveur.)

HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded");
ResponseEntity<String> st = restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class); 

Et jeté sur le DTO ResponseObject (Json)

Gson g = new Gson();
DTO dto = g.fromJson(st.getBody(), DTO.class); 
5
hirosht

Dans mon cas, la solution de @Ilya Dyoshin n'a pas fonctionné: le type de média "*" n'était pas autorisé. Je corrige cette erreur en ajoutant un nouveau convertisseur à restTemplate de cette façon lors de l'initialisation du serveur MockRestService:

  MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = 
                      new MappingJackson2HttpMessageConverter();
  mappingJackson2HttpMessageConverter.setSupportedMediaTypes(
                                    Arrays.asList(
                                       MediaType.APPLICATION_JSON, 
                                       MediaType.APPLICATION_OCTET_STREAM));
  restTemplate.getMessageConverters().add(mappingJackson2HttpMessageConverter);
  mockServer = MockRestServiceServer.createServer(restTemplate);

(Basé sur la solution proposée par Yashwant Chavan sur le blog nommé technicalkeeda)

JN Gerbaux

2
JN Gerbaux

Dans mon cas, cela est dû à l’absence des fichiers jar jackson-core, jackson-annotations et jackson-databind dans le classpath d’exécution. Il ne s'est pas plaint de l'exception habituelle ClassNothFoundException comme on pourrait s'y attendre, mais plutôt de l'erreur mentionnée dans la question initiale.

1
ikolomiyets

Vous devez créer votre propre convertisseur et l'implémenter avant de faire une demande GET.

RestTemplate  restTemplate = new RestTemplate();

List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();        

MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setSupportedMediaTypes(Collections.singletonList(MediaType.ALL));         
messageConverters.add(converter);  
restTemplate.setMessageConverters(messageConverters);    
0
Naimish Dixit

Autre solution possible: j'ai essayé de mapper le résultat d'un restTemplate.getForObject avec une instance de classe privée (définie à l'intérieur de ma classe de travail). Cela n'a pas fonctionné, mais si je définissais l'objet comme public, dans son propre fichier, cela fonctionnerait correctement.

0
Romain COMTET