RestClientException: Не удалось извлечь ответ. нет подходящего HttpMessageConverter

Используя команду curl:

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

Я получаю ответ JSON:

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

Я сохраняю ответ в текстовом файле и анализирую его с помощью Джексона, и все в порядке

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

и я предполагаю, что должен получить тот же результат, используя RestTemplate, но это не так

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

Вместо этого я получил ошибку

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)

Я попытался установить 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);

но потом я получил ошибку компиляции

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

Я также пытался добавить конвертер сообщений Джексона

  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);

Но потом я получил эту ошибку:

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)

Я также попытался добавить класс

@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;
    }

}

но я получил ошибку:

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)

Ответ 1

Основной проблемой здесь является тип контента [text/html; charset = iso-8859-1], полученный от службы, однако реальный тип контента должен быть application/json; charset = iso-8859-1

Чтобы преодолеть это, вы можете ввести специальный конвертер сообщений. и зарегистрируйте его для всех видов ответов (т.е. игнорируйте заголовок типа содержимого ответа). Именно так

  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);  

Ответ 2

У меня была очень похожая проблема, и она оказалась довольно простой; мой клиент не включал зависимость Джексона, хотя код все правильно скомпилировал, автоматические магические конвертеры для JSON не были включены. Посмотрите это решение, связанное с RestTemplate.

Короче говоря, я добавил в свой файл pom.xml зависимость Джексона, и она просто сработала:

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

Ответ 3

В то время как принятый ответ решил исходную проблему OP, я подозреваю, что большинство людей, которые находят этот вопрос с помощью поиска в Google, скорее всего (статистически говоря) сталкиваются с совершенно другой проблемой, которая просто приводит к тому же непригодному исключению HttpMessageConverter.

Под прикрытием происходит то, что MappingJackson2HttpMessageConverter поглощает любые исключения, возникающие в его canRead(), который должен автоматически определять, подходит ли полезная нагрузка для декодирования json. Исключение заменяется простым логическим возвратом, который в основном сообщает: извините, я не знаю, как декодировать это сообщение в API более высокого уровня (RestClient). Только после того, как все другие методы преобразователя canRead() возвращают false, высокоуровневое API выдает неподходящее исключение HttpMessageConverter, полностью скрывая истинную проблему.

Для людей, которые не нашли основную причину (как вы и я, но не OP), способ устранения этой проблемы состоит в том, чтобы установить onMappingJackson2HttpMessageConverter.canRead() останова отладчика в onMappingJackson2HttpMessageConverter.canRead(), а затем включить общую onMappingJackson2HttpMessageConverter.canRead() останова в любом исключении, и нажмите Продолжить. Следующим исключением является истинная первопричина.

Моя конкретная ошибка состояла в том, что один из компонентов ссылался на интерфейс, в котором отсутствовали надлежащие аннотации десериализации.

Ответ 4

Если вышеприведенный ответ @Ilya Dyoshin еще не получил, попробуйте получить ответ в String Object.

(По моему мнению, ошибка была решена фрагментом кода Ilya, полученный ответ был неудачным (ошибка) с сервера.)

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); 

И трансляция в ResponseObject DTO (Json)

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

Ответ 5

В моем случае решение @Ilya Dyoshin не сработало: медиатип "*" не был разрешен. Я исправляю эту ошибку, добавляя новый преобразователь в restTemplate таким образом во время инициализации MockRestServiceServer:

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

(На основе решения, предложенного Яшвантом Чаваном в блоге с именем technicalkeeda)

JN Gerbaux

Ответ 6

В моем случае это было вызвано отсутствием jaxon-core, jackson-annotations и jackson-databind jars из пути к классам выполнения. Он не жаловался на обычное ClassNothFoundException, как можно было ожидать, а на ошибку, упомянутую в исходном вопросе.

Ответ 7

Вам нужно создать свой собственный конвертер и реализовать его перед выполнением запроса 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);