Announcement Announcement Module
Collapse
No announcement yet.
Payload Enricher doesnot work when palyload is empty. Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Payload Enricher doesnot work when palyload is empty.

    When the payload is empty the PayloadEnricher fails to add new values. In my case I'm using int-http:inbound-gateway for request type DELETE. So I do not have a payload body. I have to enrich the payload with the values from path parameter. However since the payload is empty the payload enricher does not add any value to it and gives exception.

  • #2
    What exception?
    What does your configuration look like?

    Comment


    • #3
      WARN o.s.i.h.i.HttpRequestHandlingMessagingGateway - failure occurred in gateway sendAndReceive
      org.springframework.integration.MessageHandlingExc eption: error occurred in message handler [org.springframework.integration.transformer.Conten tEnricher#0]


      Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to java.util.List
      at org.springframework.util.LinkedMultiValueMap.put(L inkedMultiValueMap.java:1) ~[spring-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]


      My Configuration reads


      <int-http:inbound-gateway request-channel="deletePayloadEnricher"
      id="deletePaymentInstrumentGateway" error-channel="errorChannel"
      path="/consumer/{consumerId}/paymentInstruments/{paymentInstrumentToken}/gateways/{gatewayId}"
      message-converters="converters"
      supported-methods="DELETE">
      <int-http:header name="consumerId" expression="#pathVariables.consumerId" />
      <int-http:header name="paymentInstrumentToken"
      expression="#pathVariables.paymentInstrumentToken" />
      <int-http:header name="gatewayId"
      expression="#pathVariables.gatewayId" />
      </int-http:inbound-gateway>

      <int:enricher id="deletePaymentInstrumentEnricher" input-channel="deletePayloadEnricher" >
      <introperty name="paymentInstrumentToken" value="onewerewrwerwe" />
      </int:enricher>

      Comment


      • #4
        That's correct, You are getting CCE because you are assuming that what comes out of HttpInboundGateway is a String but in fact its a multipart request and what you get is LinkedMultiValueMap.
        Please look at this sample, for more details
        https://github.com/SpringSource/spri...multipart-http

        You can actually modify it for your use case.

        Comment


        • #5
          I'm sorry, but I couldn't get what you have suggested. In case of method type delete there is no request body that gets submitted, so the payload remains empty payload{}. Now I want to use the PayloadEnricher to set the values from the pathVariables so that I have values in payload that I can use in the next channel where i have to create a SOAP request using xsl transformation for values in PayloadBody.

          Comment


          • #6
            All I am saying is that the empty payload is an empty LinkedMultiValueMap which comes from Http Inbound Gateway.

            Not only that I don't think you even need the enricher since you already have all the info in the Message headers set in Http Inbound Gateway.

            Can you explain your use case? What are you trying to accomplish?

            Comment


            • #7
              Yes I agree that I have all the values in the header. I need to create a Soap Request using the xsl transformer where I have
              <xslaram name="paymentInstrumentToken" />
              <deletePaymentInstrumentRequest>
              <paymentInstrumentReference><xsl:value-of select="$paymentInstrumentToken"></xsl:value-of></paymentInstrumentReference>
              </deletePaymentInstrumentRequest>

              Since the payload is empty the xsl transformer gives exception, even though I'm using the values set as header. So I was trying to avoid this exception by trying to set the values using the Payload Enricher.

              When you say Payload is an Empty LinkedMultiValueMap, how can i set the value in the payload enricher. I've tried this and it gives exception.

              <int:enricher id="deletePaymentInstrumentEnricher" input-channel="deletePayloadEnricher" >
              <int: property name="paymentInstrumentToken" value="onewerewrwerwe" />
              </int:enricher>

              Comment


              • #8
                Ok, now I see. So few things here.
                Content Enricher (what you currently using) is designed to enrich the "properties" of the payload and in the case of payload being a Map its key/value structure does not really follow the 'properties' conventions with set/get*.
                Having said that I do believe there is a room for improvement in our implementation where you should (for the cases like you have) be able to do something like this:
                Code:
                <int:enricher input-channel="input" output-channel="output">
                	<int:expression value="payload.put('foo', headers.foo)"/>
                        <int:expression value="payload.put('bar', headers.bar)"/>
                </int:enricher>
                Basically the above allows you to execute an expression to enrich payload directly even if the payload type does not follow JavaBeans convention.
                So I suggest raising the JIRA issue (as an Improvement) and we'll take care of it.
                For the time being I's use regular Java transformer
                Code:
                public class MyTransformer {
                    public Object enrich(Message<Map<Object, Object>> message) {
                            Map<Object, Object> payload = message.getPayload();
                            Map<String, Object> headers = message.getHeaders();
                            payload.put('foo', headers.get("foo"));
                            payload.put('bar', headers.get("bar"));
                            return payload;
                    }
                }
                
                And in XML
                
                <int:transformer input-channel="input" output-channel="output">
                      <bean class="foo.bar.MyTransformer"/>
                </int:transformer>
                Hoep that helps

                Comment


                • #9
                  Thank you for the response and the work around. It works fine.

                  Comment


                  • #10
                    Still, please raise a JIRA for the improvement https://jira.springsource.org/browse/INT

                    Comment


                    • #11
                      Also, in the code that I posted I am modifying the actual Map to sort of fit what you were trying to do initially. However you can produce a whole different payload type. Basically whatever you return from that method is going to be a new Message payload and in your case I would recommend that since you really don't want to depend on some Spring specific class (e.g., LinkedMultiValueMap). So you can create a new HashMap (if you stil need a Map) or something completely different. . .

                      Comment


                      • #12
                        Hello, folks!
                        I've just reproduced it:
                        Code:
                        @Test
                        	public void testMultiValueMap() {
                        		QueueChannel replyChannel = new QueueChannel();
                        		DirectChannel requestChannel = new DirectChannel();
                        		requestChannel.subscribe(new AbstractReplyProducingMessageHandler() {
                        			@Override
                        			protected Object handleRequestMessage(Message<?> requestMessage) {
                        				return new Source("John", "Doe");
                        			}
                        		});
                        		ContentEnricher enricher = new ContentEnricher();
                        		enricher.setRequestChannel(requestChannel);
                        
                        		SpelExpressionParser parser = new SpelExpressionParser();
                        		Map<String, Expression> propertyExpressions = new HashMap<String, Expression>();
                        		propertyExpressions.put("name", parser.parseExpression("payload.lastName + ', ' + payload.firstName"));
                        		enricher.setPropertyExpressions(propertyExpressions);
                        		enricher.afterPropertiesSet();
                        
                        		Message<?> requestMessage = MessageBuilder.withPayload(new LinkedMultiValueMap()).setReplyChannel(replyChannel).build();
                        		enricher.handleMessage(requestMessage);
                        		Message<?> reply = replyChannel.receive(0);
                        		MultiValueMap result = (MultiValueMap) reply.getPayload();
                        		assertEquals("test", result.get("name"));
                        	}
                        The problem is really laying on MultiValueMap. It requeries that the value should be java.util.List.
                        The simple fix of it - just wrap the expression with {}:
                        HTML Code:
                        <int:enricher id="deletePaymentInstrumentEnricher" input-channel="deletePayloadEnricher" >
                        <introperty name="paymentInstrumentToken" value="{onewerewrwerwe}" />
                        </int:enricher> 
                        So, there is no any reason to open new JIRA.

                        Best regards,
                        Artem Bilan
                        Last edited by Artem Bilan; Jun 11th, 2012, 10:27 AM.

                        Comment


                        • #13
                          Right! I totally forgot abou that as well as us using MapAccessor which allows treating key/value as properties on both read and write.
                          So thanks Artem!

                          Comment


                          • #14
                            Sorry, I explain a bit my post:
                            1. {} is an inline List: http://static.springsource.org/sprin....html#d0e12704
                            2. You also can use on your <http:inbound-gateway> this one:
                            HTML Code:
                            <http:inbound-gateway
                            	payload-expression="requestParams.toSingleValueMap()"/>
                            3. Or use the same method in the 'expression' of simple <transformer> before <enricher>

                            Hope I'm clear

                            Comment

                            Working...
                            X