Announcement Announcement Module
Collapse
No announcement yet.
TcpInboundGateway, XML unmarsalling and TcpMessageMapper Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • TcpInboundGateway, XML unmarsalling and TcpMessageMapper

    I'm trying to receive XML messages over a TCP connection and experimenting with the following setup:

    Code:
    <beans:bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
      <beans:property name="contextPath" value="com.test"/>
    </beans:bean>
    
    <int-xml:unmarshalling-transformer unmarshaller="marshaller" input-channel="tcpRequestChannel" output-channel="objectRequestChannel"/>
    <int-xml:marshalling-transformer marshaller="marshaller" input-channel="objectReplyChannel" output-channel="tcpReplyChannel"/>
    
    <int-ip:tcp-connection-factory id="scf" type="server" port="9191" single-use="true" so-timeout="10000"/>
    <int-ip:tcp-inbound-gateway  request-channel="tcpRequestChannel" reply-channel="tcpReplyChannel" connection-factory="scf"/>
    The hope was the tcp-inbound-gateway would handle the socket side of things and the received message would then be passed to unmarshalling-transformer where it would be converted from XML to Java object.

    Unfortunately I get this error:

    Code:
    org.springframework.integration.transformer.MessageTransformationException: failed to transform message
    	at org.springframework.integration.transformer.AbstractTransformer.transform(AbstractTransformer.java:44)
    	at org.springframework.integration.transformer.MessageTransformingHandler.handleRequestMessage(MessageTransformingHandler.java:67)
    	at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:97)
    	at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:73)
    	at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:115)
    	at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:102)
    	at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
    	at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:157)
    	at org.springframework.integration.core.MessagingTemplate.doSend(MessagingTemplate.java:288)
    	at org.springframework.integration.core.MessagingTemplate.doSendAndReceive(MessagingTemplate.java:318)
    	at org.springframework.integration.core.MessagingTemplate.sendAndReceive(MessagingTemplate.java:239)
    	at org.springframework.integration.gateway.MessagingGatewaySupport.doSendAndReceive(MessagingGatewaySupport.java:233)
    	at org.springframework.integration.gateway.MessagingGatewaySupport.sendAndReceiveMessage(MessagingGatewaySupport.java:207)
    	at org.springframework.integration.ip.tcp.TcpInboundGateway.onMessage(TcpInboundGateway.java:71)
    	at org.springframework.integration.ip.tcp.connection.TcpNetConnection.run(TcpNetConnection.java:139)
    	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    	at java.lang.Thread.run(Thread.java:662)
    Caused by: org.springframework.integration.MessagingException: failed to create Source for payload type [[B]
    	at org.springframework.integration.xml.source.DomSourceFactory.createSource(DomSourceFactory.java:68)
    	at org.springframework.integration.xml.transformer.UnmarshallingTransformer.transformPayload(UnmarshallingTransformer.java:100)
    	at org.springframework.integration.transformer.AbstractPayloadTransformer.doTransform(AbstractPayloadTransformer.java:33)
    	at org.springframework.integration.transformer.AbstractTransformer.transform(AbstractTransformer.java:33)
    Am I correct in thinking I need to convert the message from byte[] to, say, String (docs say UnmarshallingTransformer requires type Document, String, File, Source or type that's convertable to Source) between the gateway and the unmarshaller?

    If so, it seems TcpMessageMapper is the perfect candidate to do this. Indeed, it is used by TcpConnectionFactoryFactoryBean and by default it converts outbound string payloads to byte[]. Why does it not do the opposite inbound?

    Any thoughts on the above or the most elegant way to solve the problem appreciated. Thanks

  • #2
    The outbound conversion from String is done as a convenience; since (currently) there is no header information conveyed over TCP, we can't use the message to determine if it's safe to convert to a String on the inbound.

    There are a couple of solutions shown in this sample...

    https://github.com/SpringSource/spri...-client-server

    Probably the simplest solution is...

    Code:
    <int:chain input-channel="tcpRequestChannel" output-channel="objectRequestChannel"/>
        <int:transformer expression="new String(payload)"/>
        <int-xml:unmarshalling-transformer unmarshaller="marshaller" />
    </int:chain>
    The other solution is to use a conversion service and set datatype="java.lang.String" on the input channel.

    You can see both of these in action in the above sample.

    Comment


    • #3
      Thanks Gary, now working fine with a transformer.

      Thanks also for the introduction to Conversion Service and Data Type channels, that knowledge is very helpful.

      Comment


      • #4
        Glad to help.

        By the way; the sample was recently changed to explicitly declare the conversion service as a <bean/>, but it's declaration can be simplified, using the namespace, to...

        Code:
        <int:converter>
            <bean class="org.springframework.integration.samples.tcpclientserver.ByteArrayToStringConverter" />
        
            ...
        
        </int:converter>

        Comment

        Working...
        X