web-dev-qa-db-fra.com

Impossible d'extraire la réponse: aucun HttpMessageConverter approprié n'a été trouvé pour le type de réponse

Je suis nouveau avec l'intégration de printemps et je travaille dans le module http d'intégration de printemps pour les besoins de mon projet. J'envoie une demande de la passerelle sortante en tant que client http. J'essaie d'initier une demande au serveur et le serveur doit me renvoyer la charge utile du message avec mes valeurs définies. Je convertis un objet en JSON en utilisant pour envoyer au serveur J'envoie une demande à la passerelle entrante présente côté serveur à partir du client (HttpClientDemo) indiqué ci-dessous. Dans ce but, je convertis mon objet en JSON, puis convertis en chaîne JSON en objet côté client, y effectuant une opération simple et le renvoyant au client (HttpClientDemo) mais avant cela, je reçois une exception liée à HttpMessageConverter comme ci-dessous:

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)

Veuillez trouver ci-dessous le code associé:

Code côté client: 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);
    }

}

Ma passerelle de demande est la suivante: RequestGateway.Java

public interface RequestGateway {


    FFSampleResponseHttp FFSampleResponsegatway(FFSampleRequestHttp request);

}

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

    <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

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

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

Lorsque j'exécute le code ci-dessus, j'obtiens l'erreur suivante:

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. 

J'ai utilisé l'exemple de code de base d'intégration de printemps pour référence. Veuillez fournir votre contribution. J'ai également essayé en utilisant le mappeur d'objets Spring dans les fichiers de configuration avec JSON pour transformer l'objet, mais je reçois également des problèmes similaires pour HttpMessageConverter. S'il vous plaît, aidez-moi avec vos précieuses contributions/suggestions et faites-moi savoir si nous avons des limitations avec le mappeur d'objet http d'intégration de ressort.


Salut Artem, Merci pour votre réponse. Je suis toujours confronté à certains défis mentionnés ci-dessous. J'ai fait les changements dans mes fichiers de configuration selon votre suggestion. mais face à un problème lors de l'utilisation de Jackson2JsonObjectMapper et besoin de votre aide supplémentaire. Veuillez trouver ci-dessous la description du problème.

J'ai fait des changements dans mes fichiers et maintenant les fichiers sont comme ci-dessous: Mon contenu de fichier Servlet-Config.xml est comme ci-dessous:

<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="jackson2JsonObjectMapper" /> 

<bean id="jackson2JsonObjectMapper" class="org.springframework.integration.support.json.Jackson2JsonObjectMapper" /> 
<bean id="ffSampleRequestHttp" class="com.myCompany.myChannel.model.FFSampleRequestHttp" /> 
<bean id="ffSampleResponseHttp" class="com.myCompany.myChannel.model.FFSampleResponseHttp" /> 
</beans>

Configuration du fichier sortant (fichier responsable du message envoyé au serveur):

<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="jackson2JsonObjectMapper" /> 
  <bean id="jackson2JsonObjectMapper" class="org.springframework.integration.support.json.Jackson2JsonObjectMapper" /> 
  </beans>

Ma méthode de classe impl est la suivante:

public  FfSampleResponseHttp issueResponseFor(FfSampleRequestHttp request) {

        FfSampleResponseHttp ffSampleResponse2 = new FfSampleResponseHttp();

        ffSampleResponse2.setCifNumber("Yappi I am in the method");
        log.info("issueResponseFor(FfSampleRequesthttp request)");

        return ffSampleResponse2;

    }

Je suis en mesure d'appeler ma méthode de service issueResponseFor présente côté serveur à partir du client, mais lorsque cela se poursuit:

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.Jackson2JsonObjectMapper.fromJson(Jackson2JsonObjectMapper.Java:93)
       at org.springframework.integration.support.json.Jackson2JsonObjectMapper.fromJson(Jackson2JsonObjectMapper.Java:44)
       at org.springframework.integration.support.json.AbstractJacksonJsonObjectMapper.fromJson(AbstractJacksonJsonObjectMapper.Java:55)
       at org.springframework.integration.json.JsonToObjectTransformer.doTransform(JsonToObjectTransformer.Java:78)
       at org.springframework.integration.transformer.AbstractTransformer.transform(AbstractTransformer.Java:33)
       ... 54 more

J'ai vérifié lors du débogage que le corps de la charge utile en réponse est vide dans l'objet json dans le paramètre Jackson2JsonObjectMapper.fromJson (…) après avoir parcouru avec succès ma méthode de service. Je ne peux pas comprendre où est-ce que je fais l'erreur. Veuillez fournir votre aide/contribution. Encore une fois, faites-moi savoir si je manque encore quelque chose dans mes fichiers de configuration. Merci beaucoup pour votre soutient.

13
Anish Lodhi

Puisque vous revenez au client juste String et son content type == 'text/plain', les convertisseurs par défaut n'ont aucune chance de déterminer comment convertir la réponse String en l'objet FFSampleResponseHttp.

Le moyen simple de le réparer:

  • retirer expected-response-type de <int-http:outbound-gateway>
  • ajouter au replyChannel1<json-to-object-transformer>

Sinon, vous devez écrire votre propre HttpMessageConverter pour convertir la chaîne en l'objet approprié.

Pour le faire fonctionner avec MappingJackson2HttpMessageConverter (l'un des convertisseurs par défaut) et votre expected-response-type, vous devez envoyer votre réponse avec content type = 'application/json'.

S'il y a un besoin, ajoutez simplement <header-enricher> après votre <service-activator> et avant d'envoyer une réponse au <int-http:inbound-gateway>.

Donc, c'est à vous de choisir la solution à sélectionner, mais votre état actuel ne fonctionne pas, en raison de l'incohérence avec la configuration par défaut.

MISE À JOUR

D'ACCORD. Puisque vous avez modifié votre serveur pour renvoyer l'objet FfSampleResponseHttp en tant que réponse HTTP, pas une chaîne, ajoutez simplement contentType = 'application/json' en-tête avant d'envoyer la réponse pour HTTP et MappingJackson2HttpMessageConverter fera l'affaire pour vous - votre objet sera converti en JSON et avec l'en-tête contentType correct.

Du côté client, vous devriez revenir à la expected-response-type="com.mycompany.MyChannel.model.FFSampleResponseHttp" et MappingJackson2HttpMessageConverter devrait recommencer.

Bien sûr, vous devez supprimer <json-to-object-transformer> de votre flux de messages après <int-http:outbound-gateway>.

7
Artem Bilan

Comme l'a dit Artem Bilan, ce problème se produit parce que MappingJackson2HttpMessageConverter prend en charge la réponse avec le type de contenu application/json uniquement. Si vous ne pouvez pas changer le code serveur, mais pouvez changer le code client (j'ai eu un tel cas), vous pouvez changer l'en-tête de type de contenu avec intercepteur:

restTemplate.getInterceptors().add((request, body, execution) -> {
            ClientHttpResponse response = execution.execute(request,body);
            response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
            return response;
        });
8
Ivan Timoshin

Voici une solution simple

essayez d'ajouter cette dépendance

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

Source: http://www.javaproficiency.com/2016/01/rest-template-could-not-extract.html

7
ericdemo07