Нет подходящего 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;
Ответы
Ответ 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.
Как только мы добавили, я мог видеть, что зарегистрированный конвертер ![введите описание изображения здесь]()