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'])"/>