spring 无法提取响应:找不到适合响应类型的 HttpMessageConverter
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24723394/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Could not extract response: no suitable HttpMessageConverter found for response type
提问by Anish Lodhi
I am new with spring integration and working in spring integration http module for my project requirement. I am sending request from outbound gateway as a http client. I am trying to initiate a request to the server and server should return me the message payload with my set values. I am converting object to JSON using to send to server I am sending a request to inbound gateway present on the server side from client(HttpClientDemo) shown below. For that purpose, I am converting my object into the JSON and then converting to JSON string to object on the client side, performing some simple operation there and sending it back to the client(HttpClientDemo) but before this, I am getting exception related to HttpMessageConverter as below:
我是 spring 集成的新手,并在 spring 集成 http 模块中为我的项目需求工作。我作为 http 客户端从出站网关发送请求。我正在尝试向服务器发起请求,服务器应该使用我的设置值返回消息负载。我正在将对象转换为 JSON 以发送到服务器 我正在从客户端(HttpClientDemo)向服务器端存在的入站网关发送请求,如下所示。为此,我将我的对象转换为 JSON,然后在客户端将对象转换为 JSON 字符串,在那里执行一些简单的操作并将其发送回客户端(HttpClientDemo),但在此之前,我遇到了与HttpMessageConverter 如下:
Exception in thread "main" org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class com.mycompany.MyChannel.model.FFSampleResponseHttp] and content type [text/plain;charset=UTF-8]
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:108)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:784)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:769)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:549)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:517)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:462)
at org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler.handleRequestMessage(HttpRequestExecutingMessageHandler.java:421)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:170)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:78)
at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116)
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:101)
at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:97)
at org.springframework.integration.channel.AbstractSubscribablMyChannel.doSend(AbstractSubscribablMyChannel.java:77)
at org.springframework.integration.channel.AbstractMessagMyChannel.send(AbstractMessagMyChannel.java:255)
at org.springframework.integration.channel.AbstractMessagMyChannel.send(AbstractMessagMyChannel.java:223)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:114)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:44)
at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:93)
Please find Below related code :
请找到以下相关代码:
Client side code: HttpClientDemo.java
客户端代码:HttpClientDemo.java
public class HttpClientDemo {
private static Logger logger = Logger.getLogger(HttpClientDemo.class);
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("/META-INF/spring/integration/http-outbound-config.xml");
RequestGateway requestGateway = context.getBean("requestGateway", RequestGateway.class);
FFSampleRequestHttp FFSampleRequesthttp = new FFSampleRequestHttp();
FFSampleRequesthttp.setMyChannelID("1");
FFSampleRequesthttp.setMyNumber("88");
FFSampleRequesthttp.setReferenceID("9I");
FFSampleRequesthttp.setTemplateType(1);
FFSampleRequesthttp.setTimestamp("today");
FFSampleResponseHttp reply = requestGateway.FFSampleResponsegatway(FFSampleRequesthttp);
logger.info("Replied with: " + reply);
}
}
My Request Gateway is as follows: RequestGateway.java
我的请求网关如下:RequestGateway.java
public interface RequestGateway {
FFSampleResponseHttp FFSampleResponsegatway(FFSampleRequestHttp request);
}
http-outbound-config.xml
http-outbound-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-http="http://www.springframework.org/schema/integration/http"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/http http://www.springframework.org/schema/integration/http/spring-integration-http.xsd">
<int:gateway id="requestGateway"
service-interface="com.mycompany.MyChannel.Common.RequestGateway"
default-request-channel="requestChannel"/>
<int:channel id="requestChannel"/>
<int:channel id="requestChannel1"/>
<!-- com.mycompany.MyChannel.model.FFSampleResponseHttp -->
<int-http:outbound-gateway request-channel="requestChannel1" reply-channel="replyChannel1" url="http://localhost:8080/MyChannel_prj-1.0.0.BUILD-SNAPSHOT/receiveGateway" http-method="POST" extract-request-payload="true" expected-response-type="com.mycompany.MyChannel.model.FFSampleResponseHttp"/>
<int:object-to-json-transformer input-channel="requestChannel" output-channel="requestChannel1" content-type="application/json" result-type="STRING"/>
<bean id="FFSampleRequestHttp" class="com.mycompany.MyChannel.model.FFSampleRequestHttp"></bean>
</beans>
Web.xml
网页.xml
<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<servlet>
<servlet-name>MyChannel-http</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/servlet-config.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>MyChannel-http</servlet-name>
<url-pattern>/receiveGateway</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
servlet-config.xml
servlet-config.xml
<int:channel id="receivMyChannel"/>
<int-http:inbound-gateway request-channel="receivMyChannel" path="/receiveGateway" supported-methods="POST"/>
<int:service-activator input-channel="receivMyChannel">
<bean class="com.mycompany.MyChannel.serviceImpl.FFSampleHttpImpl">
<constructor-arg ref = "FFSampleRequestHttp"></constructor-arg>
</bean>
</int:service-activator>
<bean id="FFSampleRequestHttp" class="com.mycompany.MyChannel.model.FFSampleRequestHttp"></bean>
<bean id="FFSampleResponseHttp" class="com.mycompany.MyChannel.model.FFSampleResponseHttp"></bean>
</beans>
public class FFSampleHttpImpl{
private static org.apache.log4j.Logger log = Logger
.getLogger(FFSampleImpl.class);
@Autowired
FFSampleRequestHttp request;
public FFSampleHttpImpl() {
}
public FFSampleHttpImpl(FFSampleRequestHttp request) {
super();
this.request = request;
}
public String issueResponseFor(String str) throws JsonParseException, JsonMappingException, IOException {
ObjectMapper mapper = new ObjectMapper();
FFSampleRequestHttp FFSampleRequestHttp = mapper.readValue(new String(str), FFSampleRequestHttp.class);
FFSampleRequestHttp.setReferenceID("Hi My Number");
String strs = new String();
strs = mapper.writeValueAsString(FFSampleRequestHttp);
return strs;
}
}
FFSampleRequestHttp.java
FFSampleRequestHttp.java
public class FFSampleRequestHttp {
protected String MyNumber;
protected String referenceID;
protected String myChannelID;
protected String timestamp;
protected int templateType;
public String getMyNumber() {
return MyNumber;
}
public void setMyNumber(String MyNumber) {
this.MyNumber = MyNumber;
}
public String getReferenceID() {
return referenceID;
}
public void setReferenceID(String referenceID) {
this.referenceID = referenceID;
}
public String getMyChannelID() {
return myChannelID;
}
public void setMyChannelID(String myChannelID) {
this.myChannelID = myChannelID;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
public int getTemplateType() {
return templateType;
}
public void setTemplateType(int templateType) {
this.templateType = templateType;
}
}
FFSampleResponseHttp.java
FFSampleResponseHttp.java
public class FFSampleResponseHttp {
protected String MyNumber;
protected String referenceID;
protected String myChannelID;
protected String timestamp;
protected int templateType;
public String getMyNumber() {
return MyNumber;
}
public void setMyNumber(String MyNumber) {
this.MyNumber = MyNumber;
}
public String getReferenceID() {
return referenceID;
}
public void setReferenceID(String referenceID) {
this.referenceID = referenceID;
}
public String getMyChannelID() {
return myChannelID;
}
public void setMyChannelID(String myChannelID) {
this.myChannelID = myChannelID;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
public int getTemplateType() {
return templateType;
}
public void setTemplateType(int templateType) {
this.templateType = templateType;
}
}
When I run the above code I get following error:
当我运行上面的代码时,我收到以下错误:
16:55:46.843 [main] DEBUG o.s.web.client.RestTemplate - Writing [{"MyNumber":"88","referenceID":"9I","myChannelID":"1","timestamp":"today","templateType":1}] as "text/plain;charset=UTF-8" using [org.springframework.http.converter.StringHttpMessageConverter@7d31a3e2]
16:55:46.988 [main] DEBUG o.s.web.client.RestTemplate - POST request for "http://localhost:8080/MyChannel_prj-1.0.0.BUILD-SNAPSHOT/receiveGateway" resulted in 200 (OK)
Exception in thread "main" org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class com.mycompany.MyChannel.model.FFSampleResponseHttp] and content type [text/plain;charset=UTF-8]
at org.springframework.web.client.HttpMessageConverterExtractor.
I have used spring integration basic sample code for reference. Please provide your input. I also tried by using the spring object mapper in the configuration files with JSON to object transformer but then also I am getting similer issues for HttpMessageConverter. Please help me with your valuable inputs/suggestion and let me know if we have any limitation with spring integration http object mapper.
我已经使用了 spring 集成基本示例代码作为参考。请提供您的意见。我还尝试在配置文件中使用 spring 对象映射器和 JSON 到对象转换器,但是我也遇到了 HttpMessageConverter 的类似问题。请帮助我提供您宝贵的意见/建议,如果我们对 Spring 集成 http 对象映射器有任何限制,请告诉我。
Hi Artem, Thanks for your reply. I am still facing some challenges mentioned below. I have done the changes in my configuration files as per of your suggestion. but facing issue when using Hymanson2JsonObjectMapper and need your further help. Please find below issue description.
嗨阿尔乔姆,感谢您的回复。我仍然面临下面提到的一些挑战。我已经按照您的建议对我的配置文件进行了更改。但在使用 Hymanson2JsonObjectMapper 时遇到问题,需要您的进一步帮助。请在下面找到问题描述。
I have done changes in my files and now files are like below: My Servlet-Config.xml file content is as below:
我已经对我的文件进行了更改,现在文件如下:我的 Servlet-Config.xml 文件内容如下:
<int:channel id="channel1" />
<int:channel id="channel2" />
<int:channel id="channel3" />
<int-http:inbound-gateway request-channel="channel1" supported-methods="POST" path="/receiveGateway" />
- <int:service-activator input-channel="channel2">
- <bean class="com.myCompany.myChannel.serviceImpl.FFSampleHttpImpl">
<constructor-arg ref="ffSampleRequestHttp" />
</bean>
</int:service-activator>
<int:json-to-object-transformer input-channel="channel1" output-channel="channel2" type="com.myCompany.myChannel.model.FFSampleRequestHttp" object-mapper="Hymanson2JsonObjectMapper" />
<bean id="Hymanson2JsonObjectMapper" class="org.springframework.integration.support.json.Hymanson2JsonObjectMapper" />
<bean id="ffSampleRequestHttp" class="com.myCompany.myChannel.model.FFSampleRequestHttp" />
<bean id="ffSampleResponseHttp" class="com.myCompany.myChannel.model.FFSampleResponseHttp" />
</beans>
Out bound file config(file which is responsible to sent message to server):
出站文件配置(负责向服务器发送消息的文件):
<int:gateway id="requestGateway" service-interface="com.myCompany.myChannel.Common.RequestGateway" default-request-channel="requestChannel" />
<int:channel id="requestChannel" />
<int:channel id="requestChannel1" />
<int:object-to-json-transformer input-channel="requestChannel" output-channel="requestChannel1" content-type="application/json" />
<int-http:outbound-gateway request-channel="requestChannel1" reply-channel="channel4" url="http://localhost:8080/myChannel_prj-1.0.0.BUILD-SNAPSHOT/http/receiveGateway" http-method="POST" />
<bean id="FFSampleRequestHttp" class="com.myCompany.myChannel.model.FFSampleRequestHttp" />
<int:json-to-object-transformer input-channel="channel4" output-channel="requestChannel" type="com.myCompany.myChannel.model.FFSampleResponseHttp" object-mapper="Hymanson2JsonObjectMapper" />
<bean id="Hymanson2JsonObjectMapper" class="org.springframework.integration.support.json.Hymanson2JsonObjectMapper" />
</beans>
My impl class method is as below:
我的impl类方法如下:
public FfSampleResponseHttp issueResponseFor(FfSampleRequestHttp request) {
FfSampleResponseHttp ffSampleResponse2 = new FfSampleResponseHttp();
ffSampleResponse2.setCifNumber("Yappi I am in the method");
log.info("issueResponseFor(FfSampleRequesthttp request)");
return ffSampleResponse2;
}
I am able to call my service method issueResponseFor present in server side from the client but when this is processing further:
我可以从客户端调用我的服务方法 issueResponseFor 存在于服务器端,但是当这进一步处理时:
Caused by: java.lang.IllegalArgumentException: 'json' argument must be an instance of: [class java.lang.String, class [B, class java.io.File, class java.net.URL, class java.io.InputStream, class java.io.Reader]
at org.springframework.integration.support.json.Hymanson2JsonObjectMapper.fromJson(Hymanson2JsonObjectMapper.java:93)
at org.springframework.integration.support.json.Hymanson2JsonObjectMapper.fromJson(Hymanson2JsonObjectMapper.java:44)
at org.springframework.integration.support.json.AbstractHymansonJsonObjectMapper.fromJson(AbstractHymansonJsonObjectMapper.java:55)
at org.springframework.integration.json.JsonToObjectTransformer.doTransform(JsonToObjectTransformer.java:78)
at org.springframework.integration.transformer.AbstractTransformer.transform(AbstractTransformer.java:33)
... 54 more
I have verified while debugging that the payload body while in response is coming blank in json object in the parameter of Hymanson2JsonObjectMapper.fromJson(…) after roaming through my service method successfully. I am not able to understand where am I doing the mistake. Please provide your help/input. Again let me know if I am again missing something in my config files. Thank you very much for your support.
我在调试时已经验证,在成功漫游我的服务方法后,响应的有效负载主体在 Hymanson2JsonObjectMapper.fromJson(...) 的参数中的 json 对象中变为空白。我无法理解我在哪里做错了。请提供您的帮助/意见。如果我的配置文件中再次丢失某些内容,请再次告诉我。非常感谢您的支持。
采纳答案by Artem Bilan
Since you return to the client just String
and its content type == 'text/plain'
, there is no any chance for default converters to determine how to convert String
response to the FFSampleResponseHttp
object.
由于您仅返回客户端String
及其content type == 'text/plain'
,因此默认转换器没有任何机会确定如何将String
响应转换为FFSampleResponseHttp
对象。
The simple way to fix it:
修复它的简单方法:
- remove
expected-response-type
from<int-http:outbound-gateway>
- add to the
replyChannel1
<json-to-object-transformer>
- 除去
expected-response-type
从<int-http:outbound-gateway>
- 添加到
replyChannel1
<json-to-object-transformer>
Otherwise you should write your own HttpMessageConverter
to convert the String to the appropriate object.
否则,您应该自己编写HttpMessageConverter
将 String 转换为适当的对象。
To make it work with MappingHymanson2HttpMessageConverter
(one of default converters) and your expected-response-type
, you should send your reply with content type = 'application/json'
.
要使其与MappingHymanson2HttpMessageConverter
(默认转换器之一)和您的 一起使用expected-response-type
,您应该使用content type = 'application/json'
.
If there is a need, just add <header-enricher>
after your <service-activator>
and before sending a reply to the <int-http:inbound-gateway>
.
如果有需要,只需<header-enricher>
在您<service-activator>
发送回复之前添加<int-http:inbound-gateway>
。
So, it's up to you which solution to select, but your current state doesn't work, because of inconsistency with default configuration.
因此,选择哪种解决方案取决于您,但由于与默认配置不一致,您当前的状态不起作用。
UPDATE
更新
OK. Since you changed your server to return FfSampleResponseHttp
object as HTTP response, not String, just add contentType = 'application/json'
header before sending the response for the HTTP and MappingHymanson2HttpMessageConverter
will do the stuff for you - your object will be converted to JSON and with correct contentType
header.
好的。由于您更改了服务器以将FfSampleResponseHttp
对象作为 HTTP 响应返回,而不是字符串,因此只需contentType = 'application/json'
在发送HTTP 响应之前添加标头,并MappingHymanson2HttpMessageConverter
为您完成这些操作 - 您的对象将被转换为 JSON 并带有正确的contentType
标头。
From client side you should come back to the expected-response-type="com.mycompany.MyChannel.model.FFSampleResponseHttp"
and MappingHymanson2HttpMessageConverter
should do the stuff for you again.
从客户端,您应该返回expected-response-type="com.mycompany.MyChannel.model.FFSampleResponseHttp"
并且MappingHymanson2HttpMessageConverter
应该再次为您做这些事情。
Of course you should remove <json-to-object-transformer>
from you message flow after <int-http:outbound-gateway>
.
当然,您应该<json-to-object-transformer>
在<int-http:outbound-gateway>
.
回答by Ivan Timoshin
As Artem Bilan said, this problem occures because MappingHymanson2HttpMessageConverter
supports response with application/json content-type only. If you can't change server code, but can change client code(I had such case), you can change content-type header with interceptor:
正如 Artem Bilan 所说,出现这个问题是因为仅MappingHymanson2HttpMessageConverter
支持 application/json 内容类型的响应。如果您不能更改服务器代码,但可以更改客户端代码(我有这种情况),您可以使用拦截器更改内容类型标头:
restTemplate.getInterceptors().add((request, body, execution) -> {
ClientHttpResponse response = execution.execute(request,body);
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
return response;
});
回答by ericdemo07
Here is a simple solution
这是一个简单的解决方案
try adding this dependency
尝试添加此依赖项
<dependency>
<groupId>com.fasterxml.Hymanson.core</groupId>
<artifactId>Hymanson-databind</artifactId>
<version>2.8.3</version>
</dependency>
回答by Sushil
public class Application {
private static List<HttpMessageConverter<?>> getMessageConverters() {
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
converters.add(new MappingHymansonHttpMessageConverter());
return converters;
}
public static void main(String[] args) {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setMessageConverters(getMessageConverters());
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<String>(headers);
//Page page = restTemplate.getForObject("http://graph.facebook.com/pivotalsoftware", Page.class);
ResponseEntity<Page> response =
restTemplate.exchange("http://graph.facebook.com/skbh86", HttpMethod.GET, entity, Page.class, "1");
Page page = response.getBody();
System.out.println("Name: " + page.getId());
System.out.println("About: " + page.getFirst_name());
System.out.println("Phone: " + page.getLast_name());
System.out.println("Website: " + page.getMiddle_name());
System.out.println("Website: " + page.getName());
}
}