Question

I am new to Spring Integration, and want to know the best way to call a service using both SOAP and JSON payloads. My configuration appears below. I have the SOAP flow working, we support multiple namespaces, so I use SI to handle the incoming message, determine the version (from the package name) and route it to the correct endpoint. As I mentioned, this works.

<int-ws:inbound-gateway id="ContactServiceGateway"
    request-channel="ContactServiceRequestChannel" marshaller="marshaller"
    unmarshaller="marshaller" />

<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
    <property name="packagesToScan">
        <list>
            <value>com.predictivesolutions.schema.v1</value>
            <value>com.predictivesolutions.schema.v2</value>
                    <value>com.predictivesolutions.schema.v3</value>
        </list>
    </property>
</bean>

<!-- map the ContactService endpoint to the Gateway -->
<bean
    class="org.springframework.ws.server.endpoint.mapping.UriEndpointMapping">
    <property name="mappings">
        <props>
            <prop key="http://localhost:8088/ws-inbound-gateway/ContactService">ContactServiceGateway</prop>

        </props>
    </property>
</bean>

<int:channel id="ContactServiceRequestChannel" />


<int:channel id="ContactServiceRequestChannelWithHeaders">
    <int:interceptors>
        <ref bean="SecurityInterceptor" />
    </int:interceptors>
</int:channel>


<!-- REST Configuration -->

<int-http:inbound-gateway id="ContactRestGateway"
    path="*" request-channel="ContactRestRequestChannel" reply-channel="ContactRestResponseChannel"
    supported-methods="GET, POST, PUT, DELETE" reply-timeout="5000"
    header-mapper="headerMapper" request-payload-type="java.lang.String" />

<bean id="headerMapper" class="com.ps.snt.integration.HeaderMapper">
</bean>

<!-- this routes different versions of the SOAP messages to the appropriate 
    channels - we could use annotations of a custom router method instead -->
<int:header-value-router input-channel="ContactServiceRequestChannelWithHeaders"
    header-name="version">
    <int:mapping value="com.predictivesolutions.schema.v1"
        channel="ContactServiceRequestChannel_v1" />
    <int:mapping value="com.predictivesolutions.schema.v2"
        channel="ContactServiceRequestChannel_v2" />
    <int:mapping value="com.predictivesolutions.schema.v3"
        channel="ContactServiceRequestChannel_v3" />
</int:header-value-router>

<!-- create beans all of the different versions -->
<bean id="ContactServiceEndpoint_v1" class="com.ps.snt.integration.ContactServiceEndpoint_v1" />
<bean id="ContactServiceEndpoint_v2" class="com.ps.snt.integration.ContactServiceEndpoint_v2" />
<bean id="ContactServiceEndpoint_v3" class="com.ps.snt.integration.ContactServiceEndpoint_v3" />

<int:service-activator input-channel="ContactServiceRequestChannel_v1"
    ref="ContactServiceEndpoint_v1" />
<int:service-activator input-channel="ContactServiceRequestChannel_v2"
    ref="ContactServiceEndpoint_v2" />
<int:service-activator input-channel="ContactServiceRequestChannel_v3"
    ref="ContactServiceEndpoint_v3" />

I would like to support JSON, and reuse as many components as possible. The flow would be to handle all incoming requests to /rest/*, determine the version and other header values from the HTTP headers, and then route the message to the same service endpoint as the SOAP calls. I do this by using a transformer and basically converting the JSON string to the versioned JAXB object. This works as well. That configuration appears below:

<int-http:inbound-gateway id="ContactRestGateway"
        path="*" request-channel="ContactRestRequestChannel" reply-channel="ContactRestResponseChannel"
        supported-methods="GET, POST, PUT, DELETE" reply-timeout="5000"
        header-mapper="headerMapper" request-payload-type="java.lang.String" />

    <bean id="headerMapper" class="com.ps.snt.integration.HeaderMapper">
    </bean>


    <int:transformer id="ContactRestResponseChannelTransformer"
        ref="transformerBean" input-channel="ContactRestResponseChannel"
        method="toObject" output-channel="ContactRestRequestChannelTransformed" />
    <bean id="transformerBean" class="com.ps.snt.integration.Transformer" />

    <int:channel id="ContactRestRequestChannel" />
    <int:channel id="ContactRestResponseChannel" />
    <int:channel id="ContactRestRequestChannelTransformed" />

    <int:header-value-router input-channel="ContactRestRequestChannelTransformed"
        header-name="version">
        <int:mapping value="com.predictivesolutions.schema.v1"
            channel="ContactServiceRequestChannel_v1" />
        <int:mapping value="com.predictivesolutions.schema.v2"
            channel="ContactServiceRequestChannel_v2" />
        <int:mapping value="com.predictivesolutions.schema.v3"
            channel="ContactServiceRequestChannel_v3" />
    </int:header-value-router>

So I can get this to work, but I have other services I will eventually need to integrate, so I would like the least amount of configuration as possible. Some questions:

  • can I just use one inbound-gateway for both JSON and SOAP? I need both /ContactService and /rest/ContactService to be processed by this gateway. I could add a router element that uses the content-type to route to the SOAP flow or the JSON flow.
  • how do I use SPeL in a transformer element, as in the following example. Basically, from the headers I can determine the version of the payload, and was hoping to use the built in jackson transformer:

<int:json-to-object-transformer input-channel="ContactRestRequestChannel" type="headers['packageName'].concat('.').concat(headers['version'])"/>

Was it helpful?

Solution

You can't use SpEL in the type attribute of the transformer. Since version 3.0, you can set the json__TypeId__ header (upstream of the transformer) to either a class or fully qualified class name - which will be used if there is no type attribute on the transformer.

As I said in my comment; the two gateways are using different technology, so it's not clear why you might think you can combine them into one.

Of course, you can consume SOAP over normal HTTP but you will need to parse out the soap headers etc.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top