Announcement Announcement Module
Collapse
No announcement yet.
Help about SpEL expression Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Help about SpEL expression

    Hi all,

    in my scenario the header could contain a 'customer attribute' MessageId:

    Code:
    [Headers={timestamp=1339161965407, id=..., JMSXDeliveryCount=1, jms_type=bp_list, jms_timestamp=1339161963190, jms_redelivered=false, MessageId=..., jms_messageId=...}]
    That 'customer attribute' is not mandatory so in some cases is not present.
    I would like to use it around my spring context file when I want to trace the incoming request:

    Code:
    ...
        <!--  Dispatch message -->
        <file:outbound-gateway directory="file:${unmatchedMessageType.directory}"
            request-channel="unmatchedMessageTypeChannel" reply-channel="generatedFileChannel"
            filename-generator-expression="'${queue.jndi.name}' + '_' + headers.MessageId + '.xml'"/>
    ...
    When MessageId is not present I would like to use instead headers.jms_messageId.
    So the logic should be: if headers contains MessageId use it else use jms_messageId.

    I was not able to code that logic directly into a SpEL expression so I wrote a simple bean that exposes a method for doing that (public String retrieveId(MessageHeaders headers)).

    Then I tried to use the bean in my spring context file

    Code:
        <!-- Helper beans -->
        <beans:bean id="messageIdentifier" class="ch.integration.jms.listener.model.MessageIdentifier"/>
    
    ...
        <!--  Dispatch message -->
        <file:outbound-gateway directory="file:${unmatchedMessageType.directory}"
            request-channel="unmatchedMessageTypeChannel" reply-channel="generatedFileChannel"
            filename-generator-expression="'${queue.jndi.name}' + '_' + @messageIdentifier.retrieveId(headers) + '.xml'"/>
    ...
    But I got below error:

    Code:
    Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1057E:(pos 49): No bean resolver registered in the context to resolve access to bean 'messageIdentifier'
            at org.springframework.expression.spel.ast.BeanReference.getValueInternal(BeanReference.java:45)
            at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:52)
            at org.springframework.expression.spel.ast.OpPlus.getValueInternal(OpPlus.java:63)
            at org.springframework.expression.spel.ast.OpPlus.getValueInternal(OpPlus.java:62)
            at org.springframework.expression.spel.ast.OpPlus.getValueInternal(OpPlus.java:62)
            at org.springframework.expression.spel.ast.OpPlus.getValueInternal(OpPlus.java:62)
            at org.springframework.expression.spel.ast.OpPlus.getValueInternal(OpPlus.java:62)
            at org.springframework.expression.spel.ast.OpPlus.getValueInternal(OpPlus.java:62)
            at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:93)
            at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:93)
            at org.springframework.integration.handler.LoggingHandler.handleMessageInternal(LoggingHandler.java:105)
            at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:73)
            ... 41 more
    Any help is greatly appreciated.

    Geetings
    nuvola

  • #2
    I think you are asking about Ternary operator with SpEL http://static.springsource.org/sprin....html#d0e12040
    Let us know if that helped

    Comment


    • #3
      Thanks for the link about Ternary operator with SpEL.

      I'm trying to use it as below:

      Code:
          <int:logging-channel-adapter channel="bpListMessageTypeResultChannel"
              expression="'#### [Channel=bpListMessageTypeChannel][***' + (headers.MessageId != null) ? headers.MessageId : headers.jms_messageId + '][Headers=' + headers + '][Payload=' + payload + ']'"
            level="INFO"/>
      but I got a type conversion problem so my above syntax is wrong ...

      Code:
      Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1001E:(pos 0): Type conversion problem, cannot convert from java.lang.String to java.lang.Boolean
      An additional question. I need to use the same Ternary operator expression in more places in my spring context file, is there a way to store the result of the expression into a variable and reference it in the spring context file where it is needed ?

      Thanks and regards
      nuvola

      Comment


      • #4
        Hello

        If you do this:
        Code:
        headers.MessageId != null ? headers.MessageId : headers.jms_messageId
        it's enough to use an "Elvis Operator": http://static.springsource.org/sprin....html#d0e12053

        Code:
        headers.MessageId ?: headers.jms_messageId
        Also try to wrap it with () as it should be done before String concatenation. That's why you've catched SpelEvaluationException

        But what is a problem to use with <logging-channel-adapter> attribute log-full-message="true" ?

        is there a way to store the result of the expression into a variable
        Can you explain a bit more about use-case? If you plan to store result of SpEL around Message properties (payload & headers) it will be bad idea: Spring Integration has stateless programming model and invokes SpEL from 'expression' attributes at runtime for each Message.

        Take care,
        Artem Bilan

        Comment


        • #5
          Hi Artem,

          your suggestion wrapping the expression with () works:

          Code:
              <int:logging-channel-adapter channel="bpListMessageTypeResultChannel"
                  expression="'#### [Channel=bpListMessageTypeChannel][' + (headers.MessageId ?: headers.jms_messageId) + '][Headers=' + headers + '][Payload=' + payload + ']'"
                  level="INFO"/>
          but it seems it doesn't work in case of stored-proc-outbound-gateway ...
          I used the same expression in the below <int-jdbcarameter name="I_MSG_ID" expression="...":

          Code:
              <int-jdbc:stored-proc-outbound-gateway request-channel="bpListMessageTypeChannel"
                                                     reply-channel="bpListMessageTypeResultChannel"
                                                     data-source="dataSource"
                                                     stored-procedure-name="${stored-procedure-name.bp}"
                                                     auto-startup="true"
                                                     ignore-column-meta-data="true">
                  <int-jdbc:sql-parameter-definition name="I_XML"
                                                     direction="IN"
                                                     type="VARCHAR"/>
                  <int-jdbc:sql-parameter-definition name="I_MSG_ID"
                                                     direction="IN"
                                                     type="VARCHAR"/>
                  <int-jdbc:sql-parameter-definition name="O_ERR_CODE"
                                                     direction="OUT"
                                                     type="INTEGER"/>
                  <int-jdbc:parameter name="I_XML" expression="payload"/>
                  <int-jdbc:parameter name="I_MSG_ID" expression="(headers.MessageId ?: headers.jms_messageId)"/>
          but I got

          Code:
          Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: Required input parameter 'I_MSG_ID' is missing
                  at org.springframework.jdbc.core.CallableStatementCreatorFactory$CallableStatementCreatorImpl.createCallableStatement(CallableStatementCreatorFactory.java:209)
                  at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:947)
                  at org.springframework.jdbc.core.JdbcTemplate.call(JdbcTemplate.java:1003)
                  at org.springframework.jdbc.core.simple.AbstractJdbcCall.executeCallInternal(AbstractJdbcCall.java:388)
                  at org.springframework.jdbc.core.simple.AbstractJdbcCall.doExecute(AbstractJdbcCall.java:351)
                  at org.springframework.jdbc.core.simple.SimpleJdbcCall.execute(SimpleJdbcCall.java:181)
                  at org.springframework.integration.jdbc.StoredProcExecutor.executeStoredProcedure(StoredProcExecutor.java:276)
                  at org.springframework.integration.jdbc.StoredProcExecutor.executeStoredProcedureInternal(StoredProcExecutor.java:267)
                  at org.springframework.integration.jdbc.StoredProcExecutor.executeStoredProcedure(StoredProcExecutor.java:247)
                  at org.springframework.integration.jdbc.StoredProcOutboundGateway.handleRequestMessage(StoredProcOutboundGateway.java:82)
                  at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:97)
                  at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:73)
                  ... 28 more
          Instead it is ok if I use <int-jdbcarameter name="I_MSG_ID" expression="headers.MessageId"/>

          Does the expression syntax change in case of stored-proc-outbound-gateway ?

          Thanks and regards
          nuvola

          Comment


          • #6
            OK.

            Try this one:
            HTML Code:
            <int-jdbc:parameter name="I_MSG_ID" expression="headers['MessageId'] ?: headers['jms_messageId']"/>

            Comment


            • #7
              This works if the headers contain the property 'MessageId' otherwise I got an error

              Code:
              Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 54): Field or property 'MessageId' cannot be found on object of type 'org.springframework.integration.MessageHeaders'
                      at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:208)
                      at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:72)
                      at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:57)
                      at org.springframework.expression.spel.ast.Elvis.getValueInternal(Elvis.java:44)
                      at org.springframework.expression.spel.ast.OpPlus.getValueInternal(OpPlus.java:63)
                      at org.springframework.expression.spel.ast.OpPlus.getValueInternal(OpPlus.java:62)
                      at org.springframework.expression.spel.ast.OpPlus.getValueInternal(OpPlus.java:62)
                      at org.springframework.expression.spel.ast.OpPlus.getValueInternal(OpPlus.java:62)
                      at org.springframework.expression.spel.ast.OpPlus.getValueInternal(OpPlus.java:62)
                      at org.springframework.expression.spel.ast.OpPlus.getValueInternal(OpPlus.java:62)
                      at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:93)
                      at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:93)
                      at org.springframework.integration.handler.LoggingHandler.handleMessageInternal(LoggingHandler.java:105)
                      at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:73)
                      ... 41 more
              I'm trying to work around your suggestion ...

              Comment


              • #8
                I still don't understand:
                if you change SpEL from beanPropety style to map style it should work.
                I've tested it before send you suggestion ;-).

                So, I repeat: this should work:
                HTML Code:
                <int-jdbc:parameter name="I_MSG_ID" expression="headers['MessageId'] ?: headers['jms_messageId']"/>
                And in the <logging-channel-adapter> do the same, please

                Comment


                • #9
                  If I change from beanPropety style to map style in both stored-proc-outbound-gateway and logging-channel-adapter it works

                  Code:
                      <int-jdbc:stored-proc-outbound-gateway request-channel="bpListMessageTypeChannel"
                  ...
                          <int-jdbc:parameter name="I_XML" expression="payload"/>
                          <int-jdbc:parameter name="I_MSG_ID" expression="headers['MessageId'] ?: headers['jms_messageId']"/>
                      </int-jdbc:stored-proc-outbound-gateway>
                  
                      <int:channel id="bpListMessageTypeResultChannel"/>
                  
                      <int:logging-channel-adapter channel="bpListMessageTypeResultChannel"
                          expression="'#### [Channel=bpListMessageTypeChannel][' + (headers['MessageId'] ?: headers['jms_messageId']) + '][Headers=' + headers + '][Payload=' + payload + ']'"
                          level="INFO"/>
                  If I change only in the stored-proc-outbound-gateway I got the error.

                  So as you suggested I changed in both :-)

                  Comment

                  Working...
                  X