spring-integrationspring-integration-httpspring-integration-ws

Spring integration: transform http message to soap message


I'm writing an application to support a protocol that in the same HTTP endpoint mixes SOAP messages (a POST with SOAP XML) with empty messages (a POST without body), which are not empty SOAP messages.

I tried to receive the empty messages using SimpleWebServiceInboundGateway but I get 400 (bad request), which is reasonable because an empty body is not a valid SOAP message.

My idea (maybe is not the best) is to use Http.inboundGateway to receive all HTTP requests and then route the messages to SimpleWebServiceInboundGateway if they are not empty, but I'm having a problem.

If I use SimpleWebServiceInboundGateway directly I am able to receive messages using this SoapMessageService:

  @ServiceActivator(inputChannel = SOAP_MESSAGE_SERVICE_CHANNEL_NAME)
  public SoapMessage receive(SoapMessage soapMessage) {
    System.out.println(soapMessage);
    return soapMessage;
  }

But when I put in the flow the Http.inboundGateway before the SimpleWebServiceInboundGateway, that service will not work anymore because:

EL1004E: Method call: Method receive(java.lang.String) cannot be found on type com.example.services.SoapMessageService

This (using String instead of SoapMessage) works fine:

  @ServiceActivator(inputChannel = SOAP_MESSAGE_SERVICE_CHANNEL_NAME)
  public String receive(String soapMessage) {
    System.out.println(soapMessage);
    return soapMessage;
  }

But definitely I don't want to perform the conversion from String to SoapMessage by myself, specially when I know that the framework can resolve it, like when I receive the messages directly in SimpleWebServiceInboundGateway and I process them as SoapMessage.

So I would like to know how can I use Spring Integration in the best possible way to receive the HTTP messages as SoapMessage in a service activator.

Thanks in advance!


Solution

  • The Http.inboundGateway() has this option:

    /**
     * Set the message body converters to use.
     * These converters are used to convert from and to HTTP requests and responses.
     * @param messageConverters The message converters.
     * @return the current Spec.
     */
    public S messageConverters(HttpMessageConverter<?>... messageConverters) {
    

    So, essentially you can write an HttpMessageConverter to create a SoapMessage from the HTTP request:

    public class SoapMessageHttpConverter extends AbstractHttpMessageConverter<SoapMessage> {
        
        private final SoapMessageFactory soapMessageFactory;
    
        SoapMessageHttpConverter(SoapMessageFactory soapMessageFactory) {
            this.soapMessageFactory = soapMessageFactory;
        }
    
        @Override
        protected boolean supports(Class<?> clazz) {
            return true;
        }
    
        @Override
        protected SoapMessage readInternal(Class<? extends SoapMessage> clazz, HttpInputMessage inputMessage)
                throws HttpMessageNotReadableException, IOException {
            
            return soapMessageFactory.createWebServiceMessage(inputMessage.getBody());
        }
    
        @Override
        protected void writeInternal(SoapMessage soapMessage, HttpOutputMessage outputMessage) 
                throws HttpMessageNotWritableException {
            
            throw new UnsupportedOperationException();
        }
        
    }