Подтвердить что ты не робот

Нет подходящего HttpMessageConverter для типа ответа

Используя spring, с этим кодом:

List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
for(HttpMessageConverter httpMessageConverter : messageConverters){
  System.out.println(httpMessageConverter);
}
ResponseEntity<ProductList> productList = restTemplate.getForEntity(productDataUrl,ProductList.class);

Я получаю

o[email protected]34649ee4
[email protected]fba59b
[email protected]383580da
or[email protected]409e850a
org.springframework[email protected]673074aa
org.springfr[email protected]1e3b79d3
org.springfr[email protected]52bb1b26

org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class com.mycopmany.ProductList] and content type [text/html;charset=UTF-8]

Отрывок из pojo:

@XmlRootElement(name="TheProductList")
public class ProductList {

@XmlElement(required = true, name = "date")
private LocalDate importDate;
4b9b3361

Ответ 1

С точки зрения Spring ни один из экземпляров HttpMessageConverter, зарегистрированных в RestTemplate, не может преобразовать содержимое text/html в объект ProductList. Предложенный интерес представляет собой HttpMessageConverter#canRead(Class, MediaType). Реализация для всех вышеперечисленных возвращает false, включая Jaxb2RootElementHttpMessageConverter.

Так как no HttpMessageConverter может читать ваш HTTP-ответ, обработка завершается с исключением.

Если вы можете контролировать ответ сервера, измените его, чтобы установить Content-type в application/xml, text/xml или что-то подходящее application/*+xml.

Если вы не контролируете ответ сервера, вам нужно написать и зарегистрировать свой собственный HttpMessageConverter (который может расширить классы Spring, см. AbstractXmlHttpMessageConverter и его подклассы), которые могут читать и конвертировать text/html.

Ответ 2

Если вы не можете изменить ответ типа сервера, вы можете расширить GsonHttpMessageConverter для обработки дополнительных типов поддержки

public class MyGsonHttpMessageConverter extends GsonHttpMessageConverter {
    public MyGsonHttpMessageConverter() {
        List<MediaType> types = Arrays.asList(
                new MediaType("text", "html", DEFAULT_CHARSET),
                new MediaType("application", "json", DEFAULT_CHARSET),
                new MediaType("application", "*+json", DEFAULT_CHARSET)
        );
        super.setSupportedMediaTypes(types);
    }
}

Ответ 3

Вы можете создать класс RestTemplateXML, который расширяет RestTemplate. Затем переопределите doExecute(URI, HttpMethod, RequestCallback, ResponseExtractor<T>) и явно получите response-headers и установите content-type на application/xml.

Теперь Spring читает заголовки и знает, что это `application/xml '. Это своего рода хак, но он работает.

public class RestTemplateXML extends RestTemplate {

  @Override
  protected <T> T doExecute(URI url, HttpMethod method, RequestCallback requestCallback,
        ResponseExtractor<T> responseExtractor) throws RestClientException {

     logger.info( RestTemplateXML.class.getSuperclass().getSimpleName() + ".doExecute() is overridden");

     Assert.notNull(url, "'url' must not be null");
     Assert.notNull(method, "'method' must not be null");
     ClientHttpResponse response = null;
     try {
        ClientHttpRequest request = createRequest(url, method);
        if (requestCallback != null) {
           requestCallback.doWithRequest(request);
        }
        response = request.execute();

        // Set ContentType to XML
        response.getHeaders().setContentType(MediaType.APPLICATION_XML);

        if (!getErrorHandler().hasError(response)) {
           logResponseStatus(method, url, response);
        }
        else {
           handleResponseError(method, url, response);
        }
        if (responseExtractor != null) {
           return responseExtractor.extractData(response);
        }
        else {
           return null;
        }
     }
     catch (IOException ex) {
        throw new ResourceAccessException("I/O error on " + method.name() +
              " request for \"" + url + "\":" + ex.getMessage(), ex);
     }
     finally {
        if (response != null) {
           response.close();
        }
     }

  }

  private void logResponseStatus(HttpMethod method, URI url, ClientHttpResponse response) {
     if (logger.isDebugEnabled()) {
        try {
           logger.debug(method.name() + " request for \"" + url + "\" resulted in " +
                 response.getRawStatusCode() + " (" + response.getStatusText() + ")");
        }
        catch (IOException e) {
           // ignore
        }
     }
  }

  private void handleResponseError(HttpMethod method, URI url, ClientHttpResponse response) throws IOException {
     if (logger.isWarnEnabled()) {
        try {
           logger.warn(method.name() + " request for \"" + url + "\" resulted in " +
                 response.getRawStatusCode() + " (" + response.getStatusText() + "); invoking error handler");
        }
        catch (IOException e) {
           // ignore
        }
     }
     getErrorHandler().handleError(response);
  }
}

Ответ 4

Попробуйте следующее:

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

Ответ 5

Если вы используете Spring Boot, вы можете убедиться, что у вас есть зависимость Jackson от вашего пути к классам. Вы можете сделать это вручную с помощью:

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

Или вы можете использовать веб-стартер:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Ответ 6

Или вы можете использовать

public void setSupportedMediaTypes (список поддерживаетсяMediaTypes)

который принадлежит AbstractHttpMessageConverter<T>, чтобы добавить некоторые ContentTypes, которые вам нравятся. Этот способ может дать ответ MappingJackson2HttpMessageConverter canRead() и преобразовать его в желаемый класс, который в этом случае является классом ProductList.

и я думаю, что этот шаг должен подключиться к инициализации контекста Spring. например, используя

реализует ApplicationListener {... }

Ответ 7

В дополнение ко всем ответам, если вы получили ответ в ответе text/html, в то время как вы ожидали чего-то еще (т.е. application/json), он может предположить, что на стороне сервера возникла ошибка (скажем, 404) и страница с ошибкой была возвращена вместо ваших данных.

Так случилось в моем случае. Надеюсь, это сэкономит время.

Ответ 8

Это не отвечает на проблему, но если кто-то приходит к этому вопросу, когда они наткнулись на это исключение, не найдя подходящего конвертера сообщений, вот моя проблема и решение.

В Spring 4.0.9 мы смогли отправить этот

    JSONObject jsonCredential = new JSONObject();
    jsonCredential.put(APPLICATION_CREDENTIALS, data);

    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);

ResponseEntity<String> res = restTemplate.exchange(myRestUrl), HttpMethod.POST,request, String.class);

В выпуске Spring 4.3.5 мы начинаем видеть ошибки с сообщением о том, что конвертер не найден. Способ работы CONverets заключается в том, что если вы используете его в своем пути к классам, они регистрируются. Jackson-asl все еще находится в пути к классам, но не распознается spring. Мы заменяем Jackson-asl более быстрым ядром jackson. Как только мы добавили, я мог видеть, что зарегистрированный конвертер введите описание изображения здесь