Spring Expression Language (SpEL)
You can configure many Spring Integration components by using expressions written in the Spring Expression Language.
In most cases, the #root
object is the Message
, which has two properties (headers
and payload
) that allow such expressions as payload
, payload.thing
, headers['my.header']
, and so on.
In some cases, additional variables are provided.
For example, <int-http:inbound-gateway/>
provides #requestParams
(parameters from the HTTP request) and #pathVariables
(values from path placeholders in the URI).
For all SpEL expressions, a BeanResolver
is available to enable references to any bean in the application context (for example, @myBean.foo(payload)
).
In addition, two PropertyAccessors
are available.
A MapAccessor
enables accessing values in a Map
by using a key and a ReflectivePropertyAccessor
, which allows access to fields and JavaBean compliant properties (by using getters and setters).
This is how you can access the Message
headers and payload properties.
SpEL Evaluation Context Customization
Starting with Spring Integration 3.0, you can add additional PropertyAccessor
instances to the SpEL evaluation contexts used by the framework.
The framework provides the (read-only) JsonPropertyAccessor
, which you can use to access fields from a JsonNode
or JSON in a String
.
You can also create your own PropertyAccessor
if you have specific needs.
Starting with version 6.4, the JsonIndexAccessor
implementation is provided that knows how to read indexes from JSON arrays, using Jackson’s ArrayNode
API.
Supports indexes supplied as an integer literal, for example, myJsonArray[1]
.
Also supports negative indexes, for example, myJsonArray[-1]
which equates to myJsonArray[myJsonArray.length - 1]
.
Furthermore, null
is returned for any index that is out of bounds (see ArrayNode.get(int)
for details).
In addition, you can add custom functions.
Custom functions are static
methods declared on a class.
Functions and property accessors are available in any SpEL expression used throughout the framework.
The following configuration shows how to directly configure the IntegrationEvaluationContextFactoryBean
with custom property accessors and functions:
<bean id="integrationEvaluationContext"
class="org.springframework.integration.config.IntegrationEvaluationContextFactoryBean">
<property name="propertyAccessors">
<util:map>
<entry key="things">
<bean class="things.MyCustomPropertyAccessor"/>
</entry>
</util:map>
</property>
<property name="functions">
<map>
<entry key="barcalc" value="#{T(things.MyFunctions).getMethod('calc', T(things.MyThing))}"/>
</map>
</property>
</bean>
Starting with version 6.4, the AbstractEvaluationContextFactoryBean
supports an injection of IndexAccessor
instances.
See AbstractEvaluationContextFactoryBean
method JavaDocs for more information.
For convenience, Spring Integration provides namespace support for both property accessors and functions, as described in the following sections. The framework automatically configures the factory bean on your behalf.
This factory bean definition overrides the default integrationEvaluationContext
bean definition.
It adds the custom accessor and one custom function to the list (which also includes the standard accessors mentioned earlier).
Note that custom functions are static methods.
In the preceding example, the custom function is a static method called calc
on a class called MyFunctions
and takes a single parameter of type MyThing
.
Suppose you have a Message
with a payload that has a type of MyThing
.
Further, suppose that you need to perform some action to create an object called MyObject
from MyThing
and then invoke a custom function called calc
on that object.
The standard property accessors do not know how to get a MyObject
from a MyThing
, so you could write and configure a custom property accessor to do so.
As a result, your final expression might be "#barcalc(payload.myObject)"
.
The factory bean has another property (typeLocator
), which lets you customize the TypeLocator
used during SpEL evaluation.
You might need to do so running in some environments that use a non-standard ClassLoader
.
In the following example, SpEL expressions always use the bean factory’s class loader:
<bean id="integrationEvaluationContext"
class="org.springframework.integration.config.IntegrationEvaluationContextFactoryBean">
<property name="typeLocator">
<bean class="org.springframework.expression.spel.support.StandardTypeLocator">
<constructor-arg value="#{beanFactory.beanClassLoader}"/>
</bean>
</property>
</bean>
SpEL Functions
Spring Integration provides namespace support to let you create SpEL custom functions.
You can specify <spel-function/>
components to provide custom SpEL functions to the EvaluationContext
used throughout the framework.
Instead of configuring the factory bean shown earlier, you can add one or more of these components, and the framework automatically adds them to the default integrationEvaluationContext
factory bean.
For example, suppose you have a useful static method to evaluate XPath. The following example shows how you can create a custom function to use that method:
<int:spel-function id="xpath"
class="com.something.test.XPathUtils" method="evaluate(java.lang.String, java.lang.Object)"/>
<int:transformer input-channel="in" output-channel="out"
expression="#xpath('//things/@mythings', payload)" />
Given the preceding example:
-
The default
IntegrationEvaluationContextFactoryBean
bean with an ID ofintegrationEvaluationContext
is registered with the application context. -
The
<spel-function/>
is parsed and added to thefunctions
Map
ofintegrationEvaluationContext
as a map entry with itsid
as the key and the staticMethod
as the value. -
The
integrationEvaluationContext
factory bean creates a newStandardEvaluationContext
instance, and it is configured with the defaultPropertyAccessor
instances, aBeanResolver
, and the custom functions. -
That
EvaluationContext
instance is injected into theExpressionEvaluatingTransformer
bean.
To provide a SpEL Function by using Java configuration, you can declare a SpelFunctionFactoryBean
bean for each function.
The following example shows how to create a custom function:
@Bean
public SpelFunctionFactoryBean xpath() {
return new SpelFunctionFactoryBean(XPathUtils.class, "evaluate");
}
SpEL functions declared in a parent context are also made available in any child contexts.
Each context has its own instance of the integrationEvaluationContext factory bean, because each needs a different BeanResolver , but the function declarations are inherited and can be overridden by declaring a SpEL function with the same name.
|
Built-in SpEL Functions
Spring Integration provides the following standard functions, which are registered with the application context automatically on start up:
-
#jsonPath
: Evaluates a 'jsonPath' on a specified object. This function invokesJsonPathUtils.evaluate(…)
, which delegates to the Jayway JsonPath library. The following listing shows some usage examples:<transformer expression="#jsonPath(payload, '$.store.book[0].author')"/> <filter expression="#jsonPath(payload,'$..book[2].isbn') matches '\d-\d{3}-\d{5}-\d'"/> <splitter expression="#jsonPath(payload, '$.store.book')"/> <router expression="#jsonPath(payload, headers.jsonPath)"> <mapping channel="output1" value="reference"/> <mapping channel="output2" value="fiction"/> </router>
#jsonPath
also supports a third (optional) parameter: an array ofcom.jayway.jsonpath.Filter
, which can be provided by a reference to a bean or bean method (for example).Using this function requires the Jayway JsonPath library ( json-path.jar
) to be on the classpath. Otherwise, the#jsonPath
SpEL function is not registered.For more information regarding JSON see 'JSON Transformers' in Transformer.
-
#xpath
: To evaluate an xpath on some provided object. For more information regarding XML and XPath, see XML Support - Dealing with XML Payloads.
Property Accessors
Spring Integration provides namespace support to let you create SpEL custom PropertyAccessor
implementations.
You can use the <spel-property-accessors/>
component to provide a list of custom PropertyAccessor
instances to the EvaluationContext
used throughout the framework.
Instead of configuring the factory bean shown earlier, you can add this component, and the framework automatically adds the accessors to the default integrationEvaluationContext
factory bean.
Also, starting with version 6.4, a dedicated <index-accessors>
sub-element is provided to configure IndexAccessor
beans similar way.
The following example shows how to do so:
<int:spel-property-accessors>
<index-accessors>
<beans:bean id="jsonIndex" class="org.springframework.integration.json.JsonIndexAccessor"/>
</index-accessors>
<bean id="jsonPA" class="org.springframework.integration.json.JsonPropertyAccessor"/>
<ref bean="fooPropertyAccessor"/>
</int:spel-property-accessors>
In the preceding example, two custom PropertyAccessor
instances are injected into the EvaluationContext
(in the order in which they are declared).
To provide PropertyAccessor
instances by using Java Configuration, you should declare a SpelPropertyAccessorRegistrar
bean with a name of spelPropertyAccessorRegistrar
(dictated by the IntegrationContextUtils.SPEL_PROPERTY_ACCESSOR_REGISTRAR_BEAN_NAME
constant).
The following example shows how to configure two custom PropertyAccessor
(and IndexAccessor
starting with version 6.4) instances with Java:
@Bean
public SpelPropertyAccessorRegistrar spelPropertyAccessorRegistrar() {
return new SpelPropertyAccessorRegistrar(new JsonPropertyAccessor())
.add(fooPropertyAccessor())
.add(new JsonIndexAccessor());
}
Custom
|