Contact Us 1-800-596-4880

Mule Expression Language Tips

This page provides quick tips for using Mule Expression Language (MEL), including information contained in the MEL Reference Card.

Prerequisites

This document assumes you are familiar with Mule Expression Language (MEL).

Variables, Integers, and Strings

  • As a shortcut, Mule accepts an expression such as #[payload], rather than #[message.payload] because it knows to automatically evaluate the expression for the message context object. This shortcut only applies with the payload field.

  • Mule assumes that any unquoted string contained in a Mule Expression is a flow variable. To set the value of flow variable 'foo' to 'bar', the expression #[foo == bar] actually evaluates as:

    #[flowVars.foo == flowVars.bar]
  • To access the flow variable, use one of the following expressions:

    #[flowVars.foo]
    #[foo]

Integers

  • To create an integer, place the integer like so:

    #[12]

Strings

  • To create a string, set the string between single quotes:

    #['mystring']

After setting a variable, like a session variable to #['mystring is a string'], after calling #[sessionVars.mystring], you would get "mystring is a string" as expected.

Tests

  • Return true if the lastname query string parameter from an HTTP listener is not null:

    #[message.inboundProperties.'http.query.params'.lastname != null]
  • Return the number of elements in http.method:

    #[message.inboundProperties.'http.query.params'.size()]
  • Return true if the number of elements in the map http.query.params is greater than 50:

    #[message.inboundProperties.'http.query.params'.size() > 50]
  • Testing for Emptiness: The special literal empty tests the emptiness of a value. It returns an empty value depending on context. empty evaluates to:

    • null

    • boolean false

    • empty strings or strings containing only white space

    • zero

    • empty collections

      The expression #[foo == empty] evaluates to true if the value if foo satisfies any of the requirements for emptiness.

  • Testing for NullPayload: Return true if message payload is null:

    #[payload == null]

Chained Elements

For chained methods or properties, the expression #[[a.b.c] == 'foo'] evaluates correctly even in the case that c is a null value. However, if b is a null value, the expression throws a NullPointerException.

In this example, if a field named address is null, the expression throws a NullPointerException.

#[payload.address.zipcode]

To make this same expression null safe, use the .? operator.

#[payload.address.?zipcode]

Using this operator avoids a NullPointerException if address is an empty value, instead it returns null.

If you’d like the expression to return a different value if no address is defined, you can use a chained or operator.

#[payload.address.?zipcode or 'Zipcode not set']

Flow and Session Variables

Flow variables and session variables are available as top level variables.

  • To create a session variable named sessionId whose value is the concatenation of the current message ID, "@" and the Mule instance node ID, use either set-session-variable or MEL code:

    <set-session-variable variableName="sessionId" value="#[message.id+'@'+mule.nodeId]" />
    <expression-component>sessionVars.sessionId = message.id+'@'+mule.nodeId;</expression-component>
  • The following shows how a bean can be dynamically retrieved from the registry, based on a name created by taking a value from a bean payload with a getTargetService() accessor:

    <set-variable variableName="beanName" value="#[message.payload.targetService+'Processor']" />
    <set-variable variableName="bean" value="#[app.registry.beanName]" />

Payload and Attachments

  • To copy the current payload in a flow variable named originalPayload then restore it:

    <set-variable variableName="originalPayload" value="#[message.payload]" />
    <set-payload value="#[originalPayload]" />
  • To retrieve the message payload in a particular format, using Mule’s auto-transformation capability, use payloadAs:

    <logger message="#[message.payloadAs(java.lang.String)]" />
  • To extract all *.txt and *.xml attachments, use a filtered projection:

    <expression-transformer expression="#[($.value in message.inboundAttachments.entrySet() if $.key ~= '(.*\\.txt|.*\\.xml)')]" />
  • To ask for a null payload:

    #[payload is NullPayload]

Regex Support

Regular expression helper functions retrieve null, a single value or an array of values, depending on matches. The forms that take a melExpression argument apply the regex to the result of its evaluation instead of message.payload.

#[regex(regularExpression [, melExpression [, matchFlags]])]

For example to select all the lines of the payload that begin with To:, From:, or Cc: use:

#[regex('^(To|From|Cc):')]

XPath Support

XPath helper functions return DOM4J nodes. By default the XPath expression is evaluated on message.payload unless an xmlElement is specified:

#[xpath3(xPathExpression [, xmlElement])]

To get the text content of an element or an attribute:

#[xpath3('//title').text]
#[xpath3('//title/@id').value]

JSON Processing

MEL has no direct support for JSON. The json-to-object-transformer can turn a JSON payload into a hierarchy of simple data structures that are easily parsed with MEL.

For the equivalent of this JSON path expression:

$..[? (@.title=='Moby Dick')].price

The following uses a filtered projection:

<json:json-to-object-transformer returnClass="java.lang.Object" />
<expression-transformer
    expression="#[($.price in message.payload if $.title =='Moby Dick')[0]]" />

Including DataWeave code

You can carry out powerful complex data transformations by including MEL DataWeave Functions that use DataWeave Language code. You can include this code via two different functions in MEL: 'dw()' and 'split()'.

  • 'dw' simply executes the DataWeave code you pass as an argument and returns the transformation’s result

  • 'split()' executes the code you pass as an argument and returns an iterator that allows you to process each instance of the output as a separate message.

dw("myobject:{id:payload.accountid, user:payload.user}")

For more information, see MEL DataWeave Functions.

Miscellaneous Operations

  • Assign to variable lastname the value of the message inbound property lastname:

    #[lastname = message.inboundProperties.lastname]
  • Append a string to the message payload:

    #[message.payload + 'mystring']
  • Call a static method:

    #[java.net.URLEncoder.encode()]
  • Create a hash map:

    #[new java.util.HashMap()]

Cheat Sheet Examples

  • Create a directory named target in the system’s temporary directory and set it as the current payload:

    <expression-component>
        targetDir = new java.io.File(server.tmpDir, 'target');
        targetDir.mkdir();
        payload = targetDir
    </expression-component>
  • Set the username and password for an HTTP request at runtime based on inbound message properties:

    <http:request-config name="HTTP_Request_Configuration" host="api.acme.com/v1" port="8081" doc:name="HTTP">
        <http:basic-authentication username="#[message.inboundProperties.username]" password="#[message.inboundProperties.password]"/>
        </http:request-config>
    
        <flow>
            ...
            <http:request config-ref="request-config" path="users" doc:name="HTTP Connector"/>
            ...
        </flow>
  • Java interoperability, for example, to create a random UUID and use it as an XSL-T parameter:

    <mulexml:context-property key="transactionId"
             value="#[java.util.UUID.randomUUID().toString()]" />
  • Retrieve fullName only if the name object is not null:

    <set-variable variableName="fullName" value="#[payload.name ? payload.name.fullName : otherCondition]"/>
  • Local variable assignment, as in this splitter expression that splits a multi-line payload in rows and drops the first row:

    splitter expression='#[rows=StringUtils.split(message.payload,'\n\r');
             ArrayUtil.subarray(rows,1,rows.size())]" />
  • Elvis operator - Returns the first non-null value of a list of values:

    #[message.payload.userName or message.payload.userId]

    Note: Mule checks the operands for emptiness, but not when a value is set to null.

    For example:

    If you set myop = "", Mule detects the operand as null. However, if you set myop = null, Mule does not detect that myop is null.

Global Configuration

Define global imports, aliases, and global functions in the global configuration element. Global functions can be loaded from the file system, a URL, or a classpath resource.

<configuration>
  <expression-language autoResolveVariables="false">
    <import class="org.mule.util.StringUtils" />
    <import name="rsu" class="org.apache.commons.lang.RandomStringUtils" />
    <alias name="appName" expression="app.name" />
    <global-functions file="extraFunctions.mvel">
      def reversePayload() { StringUtils.reverse(payload) }
      def randomString(size) { rsu.randomAlphanumeric(size) }
    </global-functions>
  </expression-language>
</configuration>

Advanced Tips

Accessing the Cache

You can access the Mule cache through the object store that serves as the cache repository. Depending on the nature of the object store, you can count, list, remove, or perform other operations on entries.

The code below shows the XML representation of a cache scope that uses a custom object store class.

<ee:object-store-caching-strategy name="CachingStrategy">
  <custom-object-storeclass="org.mule.util.store.SimpleMemoryObjectStore" />
</ee:object-store-caching-strategy>

The object store above is an implementation of a ListableObjectStore, which allows you to obtain lists of the entries it contains. You can access the contents of the cache by invoking the getStore method on the CachingStrategy property of app.registry.

The expression below obtains the size of the cache by invoking allKeys(), which returns an iterable list.

#[app.registry.CachingStrategy.getStore().allKeys().size()]

If you need to manipulate the registry in a Java class, you can access it through muleContext.getRegistry().

Boolean Operations Troubleshooting

  • Boolean evaluations sometimes return unexpected responses, particularly when the value of a variable contains "garbage." See tables below.

    Expression When value of var1 is…​ …​ The expression evaluates to…​

    #[var1 == true]

    'true'

    true

    #[var1 == true]

    'True' 'false'

    false

    #[var1 == true]

    'u5hsmg930'

    true

    Expression When the value of something is…​ …​ And the value of abc is…​ …​ MEL successfully evaluates the expression.

    #[payload.something.abc == 'b']

    'something'

    'null'

    #[payload.something.abc == 'b']

    'null'

    'abc'

    X
    Produces a NullPointer exception

    Note also that, if given the expression #[flowVars.abc.toString()] and the value of ‘abc’ is null, Mule throws a NullPointerException.

Evaluation Troubleshooting

A known issue causes certain incorrect expressions to produce results during an evaluation without causing any compiler errors. The issue occurs when an unexpected character is affixed at the end of an escaped property in an expression that is part of an evaluation, for example:

<when expression="#[message.inboundProperties.'http.request.path'] == '/some_path']">

Although the ] character is incorrectly affixed to the 'http.request.path' property in this example, Mule ignores this extra character and is able to compile the expression without errors.

Keep in mind this parsing issue while troubleshooting incorrect expressions or if you experience unexpected behaviors as a result of evaluating an expression. This behavior is present in all Mule 3 versions, in any component that evaluates a MEL expression.

See Also