1

I have two rest services and a Listener

  1. Service A
    1. Service B
    2. Listener L1

  • Step 1 - Listener L1 reads a file from local and send the multivalue map to service A. Service A retrieve some document from database and returns it as bytes to Listener L1.
    Step 2 - Listener L1 then sends another multivalue Map to Service B and saves the doc.

Step 1 is working as expected using MultiValueMap where as when I am trying to send the document bytes to Service B using same procedure During Step 2 - I'm getting Could not write request: no suitable HttpMessageConverter found for request type [org.springframework.util.LinkedMultiValueMap] and content type [application/octet-stream] . I'm following the same procedure but still getting the issue.

Please find below the code samples and let me know how to fix this issue.

Listener1.java

public Message<?> processJMSReqMsqAndSendToRest1(String message) throws Exception {
        MultiValueMap<String, Object> mainMap = new LinkedMultiValueMap<String, Object>();
        Map<String, String> secondaryMap = new HashMap<String, String>();
        secondaryMap.put("key1", "value1");
        secondaryMap.put("key2", "value2");
        secondaryMap.put("key3", "value3");
        byte[] messageBytes = message.getBytes();
        File newFile = new File("D:\\Temp\\temp.jpg");
        InputStream is = new FileInputStream(newFile);
        byte[] fileBytes = IOUtils.toByteArray(is);
        is.close();
        mainMap.add("metaData", secondaryMap);
        mainMap.add("messageBytes", messageBytes );
        Message<?> message1 = MessageBuilder.withPayload(mainMap).build();
        return message1;
    }


public Message<?> processRest1AndSendToRest2(Message<?> obj)  throws Exception{
    byte[] docBytes = (byte[])obj.getPayload();
    MultiValueMap<String, Object> mainMap = new LinkedMultiValueMap<String, Object>();
    Map<String, String> secondaryMap = new HashMap<String, String>();
    secondaryMap.put("key1", "value1");
    secondaryMap.put("key2", "value2");
    secondaryMap.put("key3", "value3");
    mainMap.add("metaData", secondaryMap);
    mainMap.add("messageBytes", docBytes);
    Message<?> message1 = MessageBuilder.withPayload(mainMap).build();
    return message1;

}

Spring Integration xml

<int-http:outbound-gateway
        id="docServiceOutBoundGateway" request-channel="docMetaDataIn"
        http-method="POST" url="http://localhost:8030/getDocument"
        expected-response-type="[B" reply-channel="sourceDocumentOutLv1">
    </int-http:outbound-gateway>

    <int:service-activator
        input-channel="sourceDocumentOutLv1"
        ref="docConversionOrchestratorImpl" method="processRest1AndSendToRest2"
        output-channel="sourceDocumentOutLv2" />

    <int-http:outbound-gateway  request-channel="sourceDocumentOutLv2"
            http-method="POST" url="http://localhost:8030/sendDocument"
            encode-uri="false"
            expected-response-type="java.lang.String" reply-channel="processedDocOutLv1">

    </int-http:outbound-gateway>

Service A:

@RequestMapping(value = "/getDocument", method = RequestMethod.POST)
    @ResponseBody
    public byte[] testRest1(@RequestPart("metaData")Map<String,String> metaData,@RequestPart("messageBytes")byte[] messageBytes) {
byte[] r2  = //get doc from database as bytes
        return r2;
    }

Service B:

@RequestMapping(value = "/sendDocument", method = RequestMethod.POST)
    @ResponseBody
    public String tesMySql1(@RequestPart("metaData")Map<String,String> metaData,@RequestPart("messageBytes")byte[] messageBytes) {

            return  "working";
    }

I have tried with sending it directly through rest template through java, that is working fine. But I want the structure to be consistent and be done through spring integration xml. I'm using spring boot 2.0.2 BOM.

Jayendran
  • 9,638
  • 8
  • 60
  • 103
Kaiizok
  • 90
  • 10

1 Answers1

1

I think the problem that after the first request with the expected-response-type="[B" you get a contetType header as a application/octet-stream and this doesn't fit for the second request where you have a MultiValueMap, but don't have any hooks how to represent it.

I suggest you to add a header-enricher before sending the second request:

<int:service-activator
        input-channel="sourceDocumentOutLv1"
        ref="docConversionOrchestratorImpl" method="processRest1AndSendToRest2"
        output-channel="enrichContentTypeHeaderChannel" />

<int:header-enricher input-channel="enrichContentTypeHeaderChannel" output-channel="sourceDocumentOutLv2">
    <int:header name="contentType" value="multipart/form-data" overwrite="true"/>
</int:header-enricher>
Artem Bilan
  • 113,505
  • 11
  • 91
  • 118
  • I have added the enricher as suggested, getting a new error - **org.springframework.messaging.MessageHandlingException: HTTP request execution failed for URI [http://localhost:8030/sendDocument]; nested exception is org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:8030/sendDocument": Software caused connection abort: recv failed; nested exception is java.net.SocketException: Software caused connection abort: recv failed** – Kaiizok Oct 03 '18 at 16:51
  • This is already different story: https://stackoverflow.com/questions/8780673/cause-of-software-caused-connection-abort-recv-failed. Not sure "why?" since the first request seems works for you... – Artem Bilan Oct 03 '18 at 16:55
  • 1
    The solution that you have provided is working fine. The second issue is caused due to the huge file size that I was sending in the second request. Modified the multipart request to send small file and along with the enricher solution that you have provided it is working perfectly. Thank you for the help. :) – Kaiizok Oct 04 '18 at 16:52
  • Cool! You got my +1 for your question and final solution! – Artem Bilan Oct 04 '18 at 16:55