JIRA: https://jira.spring.io/browse/INT-3342 Allow customization of the `TypeLocator` used by SpEL `EvaluationContext`s throughout the framework.
240 lines
12 KiB
XML
240 lines
12 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<appendix xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="spel"
|
|
xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
<title>Spring Expression Language (SpEL)</title>
|
|
|
|
<section id="spel-intro">
|
|
<title>Introduction</title>
|
|
<para>
|
|
Many Spring Integration components can be configured using expressions. These expressions
|
|
are written in the <ulink url="http://static.springsource.org/spring-framework/docs/current/spring-framework-reference/html/expressions.html">
|
|
Spring Expression Language</ulink>.
|
|
</para>
|
|
<para>
|
|
In most cases, the <emphasis>#root</emphasis> object is the
|
|
<classname>Message</classname> which, of course, has two properties - <code>headers</code> and
|
|
<code>payload</code> - allowing such expressions as <code>payload</code>, <code>payload.foo</code>,
|
|
<code>headers['my.header']</code> etc.
|
|
</para>
|
|
<para>
|
|
In some cases, additional variables are provided, for example the <code><int-http:inbound-gateway/></code>
|
|
provides <code>#requestParams</code> (parameters from the HTTP request) and <code>#pathVariables</code>
|
|
(values from path placeholders in the URI).
|
|
</para>
|
|
<para>
|
|
For all SpEL expressions, a <interfacename>BeanResolver</interfacename> is available, enabling references to
|
|
any bean in the application context. For example <code>@myBean.foo(payload)</code>. In addition, two
|
|
<interfacename>PropertyAccessors</interfacename> are available; a <classname>MapAccessor</classname>
|
|
enables accessing values in a <interfacename>Map</interfacename> using a key, and a
|
|
<classname>ReflectivePropertyAccessor</classname> which allows access to fields and or JavaBean compliant
|
|
properties (using getters and setters). This is how the <interfacename>Message</interfacename> headers
|
|
and payload properties are accessible.
|
|
</para>
|
|
</section>
|
|
<section id="spel-customization">
|
|
<title>SpEL Evaluation Context Customization</title>
|
|
<para>
|
|
Starting with Spring Integration 3.0, it is possible to add additional
|
|
<interfacename>PropertyAccessor</interfacename>s to the SpEL evaluation contexts used by
|
|
the framework. The framework provides
|
|
the <classname>JsonPropertyAccessor</classname> which can be used (read-only) to access fields from
|
|
a <classname>JsonNode</classname>, or JSON in a <classname>String</classname>. Or you can create your
|
|
own <interfacename>PropertyAccessor</interfacename> if you have specific needs.
|
|
</para>
|
|
<para>
|
|
In addition, custom functions can be added. Custom functions are <code>static</code> methods
|
|
declared on a class. Functions and property accessors are available in any SpEL
|
|
expression used throughout the framework.
|
|
</para>
|
|
<para>
|
|
The following configuration shows how to directly configure the
|
|
<classname>IntegrationEvaluationContextFactoryBean</classname> with custom property accessors
|
|
and functions. However, for convenience, namespace support is provided for both, as
|
|
described in the following sections, and the framework will automatically configure
|
|
the factory bean on your behalf.
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[<bean id="integrationEvaluationContext"
|
|
class="org.springframework.integration.config.IntegrationEvaluationContextFactoryBean">
|
|
<property name="propertyAccessors">
|
|
<util:map>
|
|
<entry key="foo">
|
|
<bean class="foo.MyCustomPropertyAccessor"/>
|
|
</entry>
|
|
</util:map>
|
|
</property>
|
|
<property name="functions">
|
|
<map>
|
|
<entry key="barcalc" value="#{T(foo.MyFunctions).getMethod('calc', T(foo.MyBar))}"/>
|
|
</map>
|
|
</property>
|
|
</bean>]]></programlisting>
|
|
<para>
|
|
This factory bean definition will override the default <code>integrationEvaluationContext</code>
|
|
bean definition, adding the custom accessor to the list (which also includes the standard
|
|
accessors mentioned above), and one custom function.
|
|
</para>
|
|
<para>
|
|
Note that custom functions are static methods.
|
|
In the above example, the custom function is a static method <code>calc</code> on class
|
|
<classname>MyFunctions</classname> and takes a single parameter of type <classname>MyBar</classname>.
|
|
</para>
|
|
<para>
|
|
Say you have a <classname>Message</classname> with a payload that has a type <classname>MyFoo</classname>
|
|
on which you need to perform some action to create a <classname>MyBar</classname> object from it,
|
|
and you then want to invoke a custom function <code>calc</code> on that object.
|
|
</para>
|
|
<para>
|
|
The standard property accessors wouldn't know how to get a <classname>MyBar</classname>
|
|
from a <classname>MyFoo</classname> so you could write
|
|
and configure a custom property accessor to do so. So, your final expression might be
|
|
<code>"#barcalc(payload.myBar)"</code>.
|
|
</para>
|
|
<para>
|
|
The factory bean has another property <code>typeLocator</code> which allows you to customize
|
|
the <interfacename>TypeLocator</interfacename> used during SpEL evaluation. This might be
|
|
necessary when running in some environments that use a non-standard <classname>ClassLoader</classname>.
|
|
In the following example, SpEL expressions will always use the bean factory's class loader:
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[<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>]]></programlisting>
|
|
</section>
|
|
<section id="spel-functions">
|
|
<title>SpEL Functions</title>
|
|
<para>
|
|
Namespace support is provided for easy addition of SpEL custom functions.
|
|
You can specify <code><spel-function/></code> components to provide
|
|
<ulink url="http://static.springsource.org/spring-framework/docs/current/spring-framework-reference/html/expressions.html#expressions-ref-functions"
|
|
>custom SpEL functions</ulink> to the <interfacename>EvaluationContext</interfacename> used throughout the framework.
|
|
Instead of configuring the factory bean above, simply add one or more of these components
|
|
and the framework will automatically add them to the default <emphasis>integrationEvaluationContext</emphasis>
|
|
factory bean.
|
|
</para>
|
|
<para>For example, assuming we have a useful static method to evaluate XPath:</para>
|
|
<programlisting language="xml"><![CDATA[<int:spel-function id="xpath"
|
|
class="com.foo.test.XPathUtils" method="evaluate(java.lang.String, java.lang.Object)"/>
|
|
|
|
<int:transformer input-channel="in" output-channel="out"
|
|
expression="#xpath('//foo/@bar', payload)" />
|
|
]]></programlisting>
|
|
<para>
|
|
With this sample:
|
|
<itemizedlist>
|
|
<listitem>
|
|
The default <classname>IntegrationEvaluationContextFactoryBean</classname> bean with id
|
|
<emphasis>integrationEvaluationContext</emphasis> is registered with the application
|
|
context.
|
|
</listitem>
|
|
<listitem>
|
|
The <code><spel-function/></code> is parsed and added to the <code>functions</code>
|
|
Map of <emphasis>integrationEvaluationContext</emphasis> as map entry with <code>id</code> as the key
|
|
and the static <classname>Method</classname> as the value.
|
|
</listitem>
|
|
<listitem>
|
|
The <emphasis>integrationEvaluationContext</emphasis> factory bean creates a new
|
|
<classname>StandardEvaluationContext</classname> instance,
|
|
and it is configured with the default
|
|
<interfacename>PropertyAccessor</interfacename>s, <interfacename>BeanResolver</interfacename>
|
|
and the custom functions.
|
|
</listitem>
|
|
<listitem>
|
|
That <interfacename>EvaluationContext</interfacename> instance is injected into the
|
|
<classname>ExpressionEvaluatingTransformer</classname> bean.
|
|
</listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
<para>
|
|
<note>
|
|
SpEL functions declared in a parent context are also made available in any child context(s). Each
|
|
context has its own instance of the <emphasis>integrationEvaluationContext</emphasis> factory bean
|
|
because each needs a different <interfacename>BeanResolver</interfacename>, but the function
|
|
declarations are inherited and can be overridden if needed by declaring a SpEL function with
|
|
the same name.
|
|
</note>
|
|
</para>
|
|
<para>
|
|
<emphasis role="bold">Built-in SpEL Functions</emphasis>
|
|
</para>
|
|
<para>
|
|
Spring Integration provides some standard functions, which are registered with the application
|
|
context automatically on start up:
|
|
<itemizedlist>
|
|
<listitem>
|
|
<emphasis role="bold">#jsonPath</emphasis> - to evaluate a 'jsonPath' on some provided object. This function
|
|
invokes <code>JsonPathUtils.evaluate(...)</code>. This static method delegates to the
|
|
<ulink url="http://code.google.com/p/json-path">Jayway JsonPath library</ulink>. The following shows
|
|
some usage examples:
|
|
<programlisting language="xml"><![CDATA[<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>]]></programlisting>
|
|
#jsonPath also supports the third optional parameter - an array of
|
|
<ulink url="https://github.com/jayway/JsonPath/blob/master/json-path/src/main/java/com/jayway/jsonpath/Filter.java"
|
|
><classname>com.jayway.jsonpath.Filter</classname></ulink>, which could be provided by a reference to a
|
|
bean or bean method, for example.
|
|
<note>
|
|
Using this function requires the Jayway JsonPath library (json-path.jar) to be on
|
|
the classpath; otherwise the <emphasis>#jsonPath</emphasis>
|
|
SpEL function won't be registered.
|
|
</note>
|
|
For more information regarding JSON see 'JSON Transformers' in <xref linkend="transformer"/>.
|
|
</listitem>
|
|
<listitem>
|
|
<emphasis role="bold">#xpath</emphasis> - to evaluate an 'xpath' on some provided object.
|
|
For more information regarding xml and xpath see <xref linkend="xml"/>.
|
|
</listitem>
|
|
<!--<listitem>
|
|
<emphasis>#auth</emphasis> - TBD
|
|
</listitem>-->
|
|
</itemizedlist>
|
|
</para>
|
|
</section>
|
|
<section id="spel-property-accessors">
|
|
<title>PropertyAccessors</title>
|
|
<para>
|
|
Namespace support is provided for the easy addition of SpEL custom
|
|
<ulink url="http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/expression/PropertyAccessor.html"
|
|
><interfacename>PropertyAccessor</interfacename></ulink>
|
|
implementations. You can specify the <code><spel-property-accessors/></code> component to provide a list of
|
|
custom <interfacename>PropertyAccessor</interfacename>s to the <interfacename>EvaluationContext</interfacename>
|
|
used throughout the framework. Instead of configuring the factory bean above, simply add one or more of these
|
|
components, and the framework will automatically add the accessors to the default
|
|
<emphasis>integrationEvaluationContext</emphasis> factory bean:
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[<int:spel-property-accessors>
|
|
<bean id="jsonPA" class="org.springframework.integration.json.JsonPropertyAccessor"/>
|
|
<ref bean="fooPropertyAccessor"/>
|
|
</int:spel-property-accessors>
|
|
]]></programlisting>
|
|
<para>
|
|
With this sample, two custom <interfacename>PropertyAccessor</interfacename>s will be injected to the
|
|
<interfacename>EvaluationContext</interfacename> in the order that they are declared.
|
|
</para>
|
|
<para>
|
|
<note>
|
|
Custom <interfacename>PropertyAccessor</interfacename>s declared in a parent context are also made available
|
|
in any child context(s). They are placed at the end of result list (but before the default
|
|
<classname>org.springframework.context.expression.MapAccessor</classname> and
|
|
<classname>org.springframework.expression.spel.support.ReflectivePropertyAccessor</classname>).
|
|
If a <interfacename>PropertyAccessor</interfacename> with the same bean id is declared in a child context(s),
|
|
it will override the parent accessor. Beans declared within a <code><spel-property-accessors/></code>
|
|
must have an 'id' attribute.
|
|
The final order of usage is: the accessors in the current context,
|
|
in the order in which they are declared, followed by any from parent contexts, in order, followed
|
|
by the <classname>MapAccessor</classname> and finally the <classname>ReflectivePropertyAccessor</classname>.
|
|
</note>
|
|
</para>
|
|
</section>
|
|
</appendix>
|