Announcement Announcement Module
Collapse
No announcement yet.
MessagingGatewayand OutboundMessageMapper Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • MessagingGatewayand OutboundMessageMapper

    Hi-

    I'm trying to get started with Spring-integration. I'm trying to configure a simple Gateway with an OutboundMessageMapper so that I can convert my domain object (User) into a serialized String format.

    My initial prototype is to listen for changes to a User object (using a JPA EntityListener), and put a message on a topic announcing the change.

    Code:
        @PrePersist
        @PreUpdate
        public void onChange(User pUser) {
            // I want to move this serialization logic to a message mapper
            String msg = userSerializer.asString(pUser);
            getUserChangeGateway().sendUserChange(msg);
        }
    I have configured the gateway like this:
    Code:
        <gateway id="userChangeGateway"
                 service-interface="mycompany.domain.UserChangeGateway"
                 default-request-channel="userChangesChannel"
                 />
    This works. Now I want to move the logic which calls the userSerializer.asString(pUser) into an OutboundMessageMapper. If I do that, can I configure the GatewayProxyFactoryBean to use the OutboundMessageMapper? Or do I need to implement my own MessagingGateway class?

    I'm looking to write the least code possible. Ideally I'd like to annotate my Gateway interface with an @MessageMapper annotation or something. The Spring-Integration docs only have a small reference to the OutboundMessageMapper interface, so I'm not sure how to plug it in.

    Thanks for any tips.
    -Adam

  • #2
    Adding a reference to a Message Mapper for the Gateway proxy might be a good idea. However, before opening an issue for that, I want to suggest an alternative. You could add a <transformer/> element that converts the User payload to a String. Something like this...

    Refactored gateway invocation:
    Code:
      public void onChange(User pUser) {
            getUserChangeGateway().sendUserChange(pUser);
        }
    Newly separated transformation logic:
    Code:
      public String serializeUser(User pUser) {
            return userSerializer.asString(pUser);
      }
    Modified config:
    Code:
        <gateway id="userChangeGateway"
                 service-interface="mycompany.domain.UserChangeGateway"
                 default-request-channel="userChangesChannel"
                 />
    
       <transformer input-channel="userChangesChannel"
                  ref="userSerializer"
                  method="serializeUser"
                  output-channel="serializedUserChangesChannel"
                  />
    At least this provides a workaround, but it may be a cleaner long term solution anyways depending on your overall use-cases. For example, this would allow you to intercept Messages that still have the User object as payload or to later apply different transformation logic.

    If you still think that setting a message-mapper directly on the gateway proxy would be a better solution, then please create an issue in JIRA. Hopefully the suggestion here would work as a decent workaround in the meantime.

    Let me know what you think.

    Comment


    • #3
      Thanks for the reply, Mark!

      Using a Transformer does seem like it works well. However, if I'm trying to use the patterns from EIP literally, if feels a bit like the Mapper pattern is the more correct pattern to use. So I think people who have read that book and then are looking to Spring-Integration as a way to implement those patterns, they will naturally look for a Mapper.

      In my case, I dug in a bit and found that the SimpleMessagingGateway is easy to use and supports plugging in different Mappers. The only downside to this is that my client code now depends on the MessagingGateway interface and calls "sendMessage()" instead of calling my own interface with a method more appropriate to my domain "sendUserChange()".

      Code:
          <beans:bean id="userMessageMapper" class="com.mycompany.UserMessageMapper"/>
          <beans:bean id="userChangeGateway" class="org.springframework.integration.gateway.SimpleMessagingGateway">
              <beans:constructor-arg><beans:ref bean="userMessageMapper"/></beans:constructor-arg>
              <beans:constructor-arg><beans:ref bean="userMessageMapper"/></beans:constructor-arg>
              <beans:property name="requestChannel"><beans:ref bean="userChangesChannel"/></beans:property>
          </beans:bean>

      Comment


      • #4
        I went ahead an logged a Jira for this so it can be tracked. If you feel that a Transformer is the better way to implement this, feel free to close the ticket.

        http://jira.springframework.org/browse/INT-670

        Comment


        • #5
          I see what you're saying. Really, we should probably support both options (mapper and transformer). I personally tend to see it as a pretty fine-line in the distinction and largely based on use-case. As I mentioned, if you wanted to also access the User object (e.g. with another subscriber on a publish-subscribe-channel), then the transformer would be the way to go.

          My take on MessageMapper from EIP is that it's a way to convert some data that is not yet in the form of a Message into a Message whereas a Transformer (or more strictly Message Translator in EIP) is a way to modify an existing Message by changing its payload type/format, enriching content, adding headers, etc. Of course, there is some overlap between those two, and I think in your particular case, you want to use a Mapper to create that initial Message with the payload type that you intend to use downstream. The current implementation is based on the following idea:

          MessageMapper: creates a Message from the method argument with the payload as the type of that argument (i.e. main purpose = create a Message) - does not overlap with transformer for conversion of that original method argument into a different object

          Transformer: convert the payload of a Message if the original type is not what you expect downstream

          So, I guess what I'm saying is that supporting customization of the MessageMapper on the Gateway will further blur the lines a bit, but it may well be worth it if it enables more concise implementation and configuration. Another, perhaps even more valid, case for supporting the message mapper would be to create a single Message object from multiple method arguments or even to create a message from methods with no-args that are intended as input (this is probably something we will support in 2.0 since the current behavior always assumes a no-arg method is pulling rather than pushing Messages).

          Comment


          • #6
            Great explanation - thanks again for your help, Mark.

            Comment

            Working...
            X