Add SimpleEvaluationContext
Issue: SPR-16588
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.expression.spel.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.expression.BeanResolver;
|
||||
import org.springframework.expression.ConstructorResolver;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.MethodResolver;
|
||||
import org.springframework.expression.OperatorOverloader;
|
||||
import org.springframework.expression.PropertyAccessor;
|
||||
import org.springframework.expression.TypeComparator;
|
||||
import org.springframework.expression.TypeConverter;
|
||||
import org.springframework.expression.TypeLocator;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.SpelEvaluationException;
|
||||
import org.springframework.expression.spel.SpelMessage;
|
||||
|
||||
/**
|
||||
* A basic implementation of {@link EvaluationContext} that focuses on a subset
|
||||
* of essential SpEL features and configuration options, and relies on default
|
||||
* strategies otherwise.
|
||||
*
|
||||
* <p>In many cases, the full extent of the SpEL is not
|
||||
* required and should be meaningfully restricted. Examples include but are not
|
||||
* limited to data binding expressions, property-based filters, and others. To
|
||||
* that effect, {@code SimpleEvaluationContext} supports only a subset of the
|
||||
* SpEL language syntax that excludes references to Java types, constructors,
|
||||
* and bean references.
|
||||
*
|
||||
* <p>Note that {@code SimpleEvaluationContext} cannot be configured with a
|
||||
* default root object. Instead it is meant to be created once and used
|
||||
* repeatedly through method variants on
|
||||
* {@link org.springframework.expression.Expression Expression} that accept
|
||||
* both an {@code EvaluationContext} and a root object.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.3.15
|
||||
*/
|
||||
public class SimpleEvaluationContext implements EvaluationContext {
|
||||
|
||||
private static final TypeLocator typeNotFoundTypeLocator = new TypeLocator() {
|
||||
|
||||
@Override
|
||||
public Class<?> findType(String typeName) throws EvaluationException {
|
||||
throw new SpelEvaluationException(SpelMessage.TYPE_NOT_FOUND, typeName);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private final List<PropertyAccessor> propertyAccessors;
|
||||
|
||||
private final List<ConstructorResolver> constructorResolvers =
|
||||
Collections.<ConstructorResolver>singletonList(new ReflectiveConstructorResolver());
|
||||
|
||||
private final List<MethodResolver> methodResolvers =
|
||||
Collections.<MethodResolver>singletonList(new ReflectiveMethodResolver());
|
||||
|
||||
private final TypeConverter typeConverter;
|
||||
|
||||
private final TypeComparator typeComparator = new StandardTypeComparator();
|
||||
|
||||
private final OperatorOverloader operatorOverloader = new StandardOperatorOverloader();
|
||||
|
||||
private final Map<String, Object> variables = new HashMap<String, Object>();
|
||||
|
||||
|
||||
public SimpleEvaluationContext() {
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
public SimpleEvaluationContext(List<PropertyAccessor> accessors, TypeConverter converter) {
|
||||
this.propertyAccessors = initPropertyAccessors(accessors);
|
||||
this.typeConverter = converter != null ? converter : new StandardTypeConverter();
|
||||
}
|
||||
|
||||
|
||||
private static List<PropertyAccessor> initPropertyAccessors(List<PropertyAccessor> accessors) {
|
||||
if (accessors == null) {
|
||||
accessors = new ArrayList<PropertyAccessor>(5);
|
||||
accessors.add(new ReflectivePropertyAccessor());
|
||||
}
|
||||
return accessors;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@code SimpleEvaluationContext} cannot be configured with a root object.
|
||||
* It is meant for repeated use with
|
||||
* {@link org.springframework.expression.Expression Expression} method
|
||||
* variants that accept both an {@code EvaluationContext} and a root object.
|
||||
* @return Always returns {@link TypedValue#NULL}.
|
||||
*/
|
||||
@Override
|
||||
public TypedValue getRootObject() {
|
||||
return TypedValue.NULL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PropertyAccessor> getPropertyAccessors() {
|
||||
return this.propertyAccessors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a single {@link ReflectiveConstructorResolver}.
|
||||
*/
|
||||
@Override
|
||||
public List<ConstructorResolver> getConstructorResolvers() {
|
||||
return this.constructorResolvers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a single {@link ReflectiveMethodResolver}.
|
||||
*/
|
||||
@Override
|
||||
public List<MethodResolver> getMethodResolvers() {
|
||||
return this.methodResolvers;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code SimpleEvaluationContext} does not support use of bean references.
|
||||
* @return Always returns {@code null}
|
||||
*/
|
||||
@Override
|
||||
public BeanResolver getBeanResolver() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code SimpleEvaluationContext} does not support use of type references.
|
||||
* @return {@code TypeLocator} implementation that raises a
|
||||
* {@link SpelEvaluationException} with {@link SpelMessage#TYPE_NOT_FOUND}.
|
||||
*/
|
||||
@Override
|
||||
public TypeLocator getTypeLocator() {
|
||||
return typeNotFoundTypeLocator;
|
||||
}
|
||||
|
||||
/**
|
||||
* The configured {@link TypeConverter}.
|
||||
* <p>By default this is {@link StandardTypeConverter}.
|
||||
*/
|
||||
@Override
|
||||
public TypeConverter getTypeConverter() {
|
||||
return this.typeConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an instance of {@link StandardTypeComparator}.
|
||||
*/
|
||||
@Override
|
||||
public TypeComparator getTypeComparator() {
|
||||
return this.typeComparator;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return an instance of {@link StandardOperatorOverloader}.
|
||||
*/
|
||||
@Override
|
||||
public OperatorOverloader getOperatorOverloader() {
|
||||
return this.operatorOverloader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVariable(String name, Object value) {
|
||||
this.variables.put(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object lookupVariable(String name) {
|
||||
return this.variables.get(name);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
[[expressions-intro]]
|
||||
== Introduction
|
||||
|
||||
The Spring Expression Language (SpEL for short) is a powerful expression language that
|
||||
supports querying and manipulating an object graph at runtime. The language syntax is
|
||||
similar to Unified EL but offers additional features, most notably method invocation and
|
||||
@@ -35,12 +36,7 @@ syntax. In several places an Inventor and Inventor's Society class are used as t
|
||||
target objects for expression evaluation. These class declarations and the data used to
|
||||
populate them are listed at the end of the chapter.
|
||||
|
||||
|
||||
|
||||
|
||||
[[expressions-features]]
|
||||
== Feature Overview
|
||||
The expression language supports the following functionality
|
||||
The expression language supports the following functionality:
|
||||
|
||||
* Literal expressions
|
||||
* Boolean and relational operators
|
||||
@@ -66,7 +62,8 @@ The expression language supports the following functionality
|
||||
|
||||
|
||||
[[expressions-evaluation]]
|
||||
== Expression Evaluation using Spring's Expression Interface
|
||||
== Evaluation
|
||||
|
||||
This section introduces the simple use of SpEL interfaces and its expression language.
|
||||
The complete language reference can be found in the section
|
||||
<<expressions-language-ref,Language Reference>>.
|
||||
@@ -153,10 +150,9 @@ result type. An `EvaluationException` will be thrown if the value cannot be cast
|
||||
type `T` or converted using the registered type converter.
|
||||
|
||||
The more common usage of SpEL is to provide an expression string that is evaluated
|
||||
against a specific object instance (called the root object). There are two options here
|
||||
and which to choose depends on whether the object against which the expression is being
|
||||
evaluated will be changing with each call to evaluate the expression. In the following
|
||||
example we retrieve the `name` property from an instance of the Inventor class.
|
||||
against a specific object instance (called the root object). The example shows
|
||||
how to retrieve the `name` property from an instance of the `Inventor` class or
|
||||
create a boolean condition:
|
||||
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
@@ -169,91 +165,43 @@ example we retrieve the `name` property from an instance of the Inventor class.
|
||||
Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian");
|
||||
|
||||
ExpressionParser parser = new SpelExpressionParser();
|
||||
Expression exp = parser.parseExpression("**name**");
|
||||
|
||||
EvaluationContext context = new StandardEvaluationContext(tesla);
|
||||
String name = (String) exp.getValue(context);
|
||||
----
|
||||
|
||||
In the last line, the value of the string variable `name` will be set to "Nikola Tesla".
|
||||
The class StandardEvaluationContext is where you can specify which object the "name"
|
||||
property will be evaluated against. This is the mechanism to use if the root object is
|
||||
unlikely to change, it can simply be set once in the evaluation context. If the root
|
||||
object is likely to change repeatedly, it can be supplied on each call to `getValue`, as
|
||||
this next example shows:
|
||||
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
/ Create and set a calendar
|
||||
GregorianCalendar c = new GregorianCalendar();
|
||||
c.set(1856, 7, 9);
|
||||
|
||||
// The constructor arguments are name, birthday, and nationality.
|
||||
Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian");
|
||||
|
||||
ExpressionParser parser = new SpelExpressionParser();
|
||||
Expression exp = parser.parseExpression("**name**");
|
||||
String name = (String) exp.getValue(tesla);
|
||||
----
|
||||
// name == "Nikola Tesla"
|
||||
|
||||
In this case the inventor `tesla` has been supplied directly to `getValue` and the
|
||||
expression evaluation infrastructure creates and manages a default evaluation context
|
||||
internally - it did not require one to be supplied.
|
||||
|
||||
The StandardEvaluationContext is relatively expensive to construct and during repeated
|
||||
usage it builds up cached state that enables subsequent expression evaluations to be
|
||||
performed more quickly. For this reason it is better to cache and reuse them where
|
||||
possible, rather than construct a new one for each expression evaluation.
|
||||
|
||||
In some cases it can be desirable to use a configured evaluation context and yet still
|
||||
supply a different root object on each call to `getValue`. `getValue` allows both to be
|
||||
specified on the same call. In these situations the root object passed on the call is
|
||||
considered to override any (which maybe null) specified on the evaluation context.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
In standalone usage of SpEL there is a need to create the parser, parse expressions and
|
||||
perhaps provide evaluation contexts and a root context object. However, more common
|
||||
usage is to provide only the SpEL expression string as part of a configuration file, for
|
||||
example for Spring bean or Spring Web Flow definitions. In this case, the parser,
|
||||
evaluation context, root object and any predefined variables are all set up implicitly,
|
||||
requiring the user to specify nothing other than the expressions.
|
||||
====
|
||||
|
||||
As a final introductory example, the use of a boolean operator is shown using the
|
||||
Inventor object in the previous example.
|
||||
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
Expression exp = parser.parseExpression("name == 'Nikola Tesla'");
|
||||
boolean result = exp.getValue(context, Boolean.class); // evaluates to true
|
||||
exp = parser.parseExpression("name == 'Nikola Tesla'");
|
||||
boolean result = exp.getValue(tesla, Boolean.class);
|
||||
// result == true
|
||||
----
|
||||
|
||||
|
||||
|
||||
[[expressions-evaluation-context]]
|
||||
=== The EvaluationContext interface
|
||||
=== `EvaluationContext`
|
||||
|
||||
The interface `EvaluationContext` is used when evaluating an expression to resolve
|
||||
properties, methods, fields, and to help perform type conversion. The out-of-the-box
|
||||
implementation, `StandardEvaluationContext`, uses reflection to manipulate the object,
|
||||
caching `java.lang.reflect.Method`, `java.lang.reflect.Field`, and
|
||||
`java.lang.reflect.Constructor` instances for increased performance.
|
||||
implementations, `SimpleEvalutationContext` and `StandardEvaluationContext`, use
|
||||
reflection to manipulate the object, caching `java.lang.reflect.Method`,
|
||||
`java.lang.reflect.Field`, and `java.lang.reflect.Constructor` instances for increased
|
||||
performance.
|
||||
|
||||
The `StandardEvaluationContext` is where you may specify the root object to evaluate
|
||||
against via the method `setRootObject()` or passing the root object into the
|
||||
constructor. You can also specify variables and functions that will be used in the
|
||||
expression using the methods `setVariable()` and `registerFunction()`. The use of
|
||||
variables and functions are described in the language reference sections
|
||||
<<expressions-ref-variables,Variables>> and <<expressions-ref-functions,Functions>>. The
|
||||
`StandardEvaluationContext` is also where you can register custom
|
||||
``ConstructorResolver``s, ``MethodResolver``s, and ``PropertyAccessor``s to extend how SpEL
|
||||
evaluates expressions. Please refer to the javadoc of these classes for more details.
|
||||
`SimpleEvaluationContext` exposes a subset of essential SpEL language features and
|
||||
configuration options. Certain categories of expressions, do not require the full extent
|
||||
of the SpEL language syntax and arguably should be meaningfully restricted. Examples
|
||||
include but are not limited to data binding expressions, property-based filters, and
|
||||
others. To effect, `SimpleEvaluationContext` supports a subset of the SpEL language syntax
|
||||
that excludes references to Java types, constructors, and bean references.
|
||||
|
||||
`StandardEvaluationContext` exposes the full set of SpEL language features and
|
||||
configuration options. You may use it to specify a default root object, and to configure
|
||||
every available evaluation-related strategy.
|
||||
|
||||
|
||||
[[expressions-type-conversion]]
|
||||
==== Type Conversion
|
||||
==== Type conversion
|
||||
|
||||
By default SpEL uses the conversion service available in Spring core (
|
||||
`org.springframework.core.convert.ConversionService`). This conversion service comes
|
||||
with many converters built in for common conversions but is also fully extensible so
|
||||
@@ -275,22 +223,25 @@ being placed in it. A simple example:
|
||||
}
|
||||
|
||||
Simple simple = new Simple();
|
||||
|
||||
simple.booleanList.add(true);
|
||||
|
||||
StandardEvaluationContext simpleContext = new StandardEvaluationContext(simple);
|
||||
SimpleEvaluationContext context = new SimpleEvaluationContext();
|
||||
|
||||
// false is passed in here as a string. SpEL and the conversion service will
|
||||
// correctly recognize that it needs to be a Boolean and convert it
|
||||
parser.parseExpression("booleanList[0]").setValue(simpleContext, "false");
|
||||
|
||||
parser.parseExpression("booleanList[0]").setValue(context, simple, "false");
|
||||
|
||||
// b will be false
|
||||
Boolean b = simple.booleanList.get(0);
|
||||
----
|
||||
|
||||
|
||||
|
||||
[[expressions-parser-configuration]]
|
||||
=== Parser configuration
|
||||
It is possible to configure the SpEL expression parser using a parser configuration object
|
||||
|
||||
It is possible to configure the SpEL expression parser using a parser configuration object
|
||||
(`org.springframework.expression.spel.SpelParserConfiguration`). The configuration
|
||||
object controls the behavior of some of the expression components. For example, if
|
||||
indexing into an array or collection and the element at the specified index is `null`
|
||||
@@ -325,6 +276,8 @@ list it is possible to automatically grow the array or list to accommodate that
|
||||
|
||||
It is also possible to configure the behaviour of the SpEL expression compiler.
|
||||
|
||||
|
||||
|
||||
[[expressions-spel-compilation]]
|
||||
=== SpEL compilation
|
||||
|
||||
@@ -356,6 +309,7 @@ gain can be very noticeable. In an example micro benchmark run of 50000 iteratio
|
||||
taking 75ms to evaluate using only the interpreter and just 3ms using the compiled version
|
||||
of the expression.
|
||||
|
||||
|
||||
[[expressions-compiler-configuration]]
|
||||
==== Compiler configuration
|
||||
|
||||
@@ -415,6 +369,7 @@ In these cases it is possible to use a system property. The property
|
||||
`spring.expression.compiler.mode` can be set to one of the `SpelCompilerMode`
|
||||
enum values (`off`, `immediate`, or `mixed`).
|
||||
|
||||
|
||||
[[expressions-compiler-limitations]]
|
||||
==== Compiler limitations
|
||||
|
||||
@@ -430,8 +385,12 @@ at the moment:
|
||||
|
||||
More and more types of expression will be compilable in the future.
|
||||
|
||||
|
||||
|
||||
|
||||
[[expressions-beandef]]
|
||||
== Expression support for defining bean definitions
|
||||
== Expressions in bean definitions
|
||||
|
||||
SpEL expressions can be used with XML or annotation-based configuration metadata for
|
||||
defining ``BeanDefinition``s. In both cases the syntax to define the expression is of the
|
||||
form `#{ <expression string> }`.
|
||||
@@ -439,7 +398,8 @@ form `#{ <expression string> }`.
|
||||
|
||||
|
||||
[[expressions-beandef-xml-based]]
|
||||
=== XML based configuration
|
||||
=== XML configuration
|
||||
|
||||
A property or constructor-arg value can be set using expressions as shown below.
|
||||
|
||||
[source,xml,indent=0]
|
||||
@@ -487,7 +447,8 @@ You can also refer to other bean properties by name, for example.
|
||||
|
||||
|
||||
[[expressions-beandef-annotation-based]]
|
||||
=== Annotation-based configuration
|
||||
=== Annotation config
|
||||
|
||||
The `@Value` annotation can be placed on fields, methods and method/constructor
|
||||
parameters to specify a default value.
|
||||
|
||||
@@ -584,6 +545,7 @@ Autowired methods and constructors can also use the `@Value` annotation.
|
||||
|
||||
[[expressions-ref-literal]]
|
||||
=== Literal expressions
|
||||
|
||||
The types of literal expressions supported are strings, numeric values (int, real, hex),
|
||||
boolean and null. Strings are delimited by single quotes. To put a single quote itself
|
||||
in a string, use two single quote characters.
|
||||
@@ -617,6 +579,7 @@ By default real numbers are parsed using Double.parseDouble().
|
||||
|
||||
[[expressions-properties-arrays]]
|
||||
=== Properties, Arrays, Lists, Maps, Indexers
|
||||
|
||||
Navigating with property references is easy: just use a period to indicate a nested
|
||||
property value. The instances of the `Inventor` class, pupin, and tesla, were populated with
|
||||
data listed in the section <<expressions-example-classes,Classes used in the examples>>.
|
||||
@@ -639,25 +602,24 @@ arrays and lists are obtained using square bracket notation.
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
ExpressionParser parser = new SpelExpressionParser();
|
||||
SimpleEvaluationContext context = new SimpleEvaluationContext();
|
||||
|
||||
// Inventions Array
|
||||
StandardEvaluationContext teslaContext = new StandardEvaluationContext(tesla);
|
||||
|
||||
// evaluates to "Induction motor"
|
||||
String invention = parser.parseExpression("inventions[3]").getValue(
|
||||
teslaContext, String.class);
|
||||
context, tesla, String.class);
|
||||
|
||||
// Members List
|
||||
StandardEvaluationContext societyContext = new StandardEvaluationContext(ieee);
|
||||
|
||||
// evaluates to "Nikola Tesla"
|
||||
String name = parser.parseExpression("Members[0].Name").getValue(
|
||||
societyContext, String.class);
|
||||
context, ieee, String.class);
|
||||
|
||||
// List and Array navigation
|
||||
// evaluates to "Wireless communication"
|
||||
String invention = parser.parseExpression("Members[0].Inventions[6]").getValue(
|
||||
societyContext, String.class);
|
||||
context, ieee, String.class);
|
||||
----
|
||||
|
||||
The contents of maps are obtained by specifying the literal key value within the
|
||||
@@ -685,6 +647,7 @@ string literals.
|
||||
|
||||
[[expressions-inline-lists]]
|
||||
=== Inline lists
|
||||
|
||||
Lists can be expressed directly in an expression using `{}` notation.
|
||||
|
||||
[source,java,indent=0]
|
||||
@@ -700,8 +663,11 @@ Lists can be expressed directly in an expression using `{}` notation.
|
||||
entirely composed of fixed literals then a constant list is created to represent the
|
||||
expression, rather than building a new list on each evaluation.
|
||||
|
||||
|
||||
|
||||
[[expressions-inline-maps]]
|
||||
=== Inline Maps
|
||||
|
||||
Maps can also be expressed directly in an expression using `{key:value}` notation.
|
||||
|
||||
[source,java,indent=0]
|
||||
@@ -717,8 +683,11 @@ of fixed literals or other nested constant structures (lists or maps) then a con
|
||||
to represent the expression, rather than building a new map on each evaluation. Quoting of the map keys
|
||||
is optional, the examples above are not using quoted keys.
|
||||
|
||||
|
||||
|
||||
[[expressions-array-construction]]
|
||||
=== Array construction
|
||||
|
||||
Arrays can be built using the familiar Java syntax, optionally supplying an initializer
|
||||
to have the array populated at construction time.
|
||||
|
||||
@@ -741,6 +710,7 @@ multi-dimensional array.
|
||||
|
||||
[[expressions-methods]]
|
||||
=== Methods
|
||||
|
||||
Methods are invoked using typical Java programming syntax. You may also invoke methods
|
||||
on literals. Varargs are also supported.
|
||||
|
||||
@@ -763,6 +733,7 @@ on literals. Varargs are also supported.
|
||||
|
||||
[[expressions-operators-relational]]
|
||||
==== Relational operators
|
||||
|
||||
The relational operators; equal, not equal, less than, less than or equal, greater than,
|
||||
and greater than or equal are supported using standard operator notation.
|
||||
|
||||
@@ -825,6 +796,7 @@ shown here: `lt` (`<`), `gt` (`>`), `le` (`<=`), `ge` (`>=`), `eq` (`==`),
|
||||
|
||||
[[expressions-operators-logical]]
|
||||
==== Logical operators
|
||||
|
||||
The logical operators that are supported are and, or, and not. Their use is demonstrated
|
||||
below.
|
||||
|
||||
@@ -862,6 +834,7 @@ below.
|
||||
|
||||
[[expressions-operators-mathematical]]
|
||||
==== Mathematical operators
|
||||
|
||||
The addition operator can be used on both numbers and strings. Subtraction, multiplication
|
||||
and division can be used only on numbers. Other mathematical operators supported are
|
||||
modulus (%) and exponential power (^). Standard operator precedence is enforced. These
|
||||
@@ -904,6 +877,7 @@ operators are demonstrated below.
|
||||
|
||||
[[expressions-assignment]]
|
||||
=== Assignment
|
||||
|
||||
Setting of a property is done by using the assignment operator. This would typically be
|
||||
done within a call to `setValue` but can also be done inside a call to `getValue`.
|
||||
|
||||
@@ -911,20 +885,21 @@ done within a call to `setValue` but can also be done inside a call to `getValue
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
Inventor inventor = new Inventor();
|
||||
StandardEvaluationContext inventorContext = new StandardEvaluationContext(inventor);
|
||||
SimpleEvaluationContext context = new SimpleEvaluationContext();
|
||||
|
||||
parser.parseExpression("Name").setValue(inventorContext, "Alexander Seovic2");
|
||||
parser.parseExpression("Name").setValue(context, inventor, "Alexander Seovic2");
|
||||
|
||||
// alternatively
|
||||
|
||||
String aleks = parser.parseExpression(
|
||||
"Name = 'Alexandar Seovic'").getValue(inventorContext, String.class);
|
||||
"Name = 'Alexandar Seovic'").getValue(context, inventor, String.class);
|
||||
----
|
||||
|
||||
|
||||
|
||||
[[expressions-types]]
|
||||
=== Types
|
||||
|
||||
The special `T` operator can be used to specify an instance of java.lang.Class (the
|
||||
_type_). Static methods are invoked using this operator as well. The
|
||||
`StandardEvaluationContext` uses a `TypeLocator` to find types and the
|
||||
@@ -948,6 +923,7 @@ fully qualified, but all other type references must be.
|
||||
|
||||
[[expressions-constructors]]
|
||||
=== Constructors
|
||||
|
||||
Constructors can be invoked using the new operator. The fully qualified class name
|
||||
should be used for all but the primitive type and String (where int, float, etc, can be
|
||||
used).
|
||||
@@ -969,17 +945,18 @@ used).
|
||||
|
||||
[[expressions-ref-variables]]
|
||||
=== Variables
|
||||
|
||||
Variables can be referenced in the expression using the syntax `#variableName`. Variables
|
||||
are set using the method setVariable on the `StandardEvaluationContext`.
|
||||
are set using the method setVariable on `EvaluationContext` implementations.
|
||||
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
|
||||
StandardEvaluationContext context = new StandardEvaluationContext(tesla);
|
||||
SimpleEvaluationContext context = new SimpleEvaluationContext();
|
||||
context.setVariable("newName", "Mike Tesla");
|
||||
|
||||
parser.parseExpression("Name = #newName").getValue(context);
|
||||
parser.parseExpression("Name = #newName").getValue(context, tesla);
|
||||
|
||||
System.out.println(tesla.getName()) // "Mike Tesla"
|
||||
----
|
||||
@@ -987,6 +964,7 @@ are set using the method setVariable on the `StandardEvaluationContext`.
|
||||
|
||||
[[expressions-this-root]]
|
||||
==== The #this and #root variables
|
||||
|
||||
The variable #this is always defined and refers to the current evaluation object
|
||||
(against which unqualified references are resolved). The variable #root is always
|
||||
defined and refers to the root context object. Although #this may vary as components of
|
||||
@@ -1001,7 +979,7 @@ an expression are evaluated, #root always refers to the root.
|
||||
|
||||
// create parser and set variable 'primes' as the array of integers
|
||||
ExpressionParser parser = new SpelExpressionParser();
|
||||
StandardEvaluationContext context = new StandardEvaluationContext();
|
||||
SimpleEvaluationContext context = new SimpleEvaluationContext();
|
||||
context.setVariable("primes",primes);
|
||||
|
||||
// all prime numbers > 10 from the list (using selection ?{...})
|
||||
@@ -1014,18 +992,20 @@ an expression are evaluated, #root always refers to the root.
|
||||
|
||||
[[expressions-ref-functions]]
|
||||
=== Functions
|
||||
|
||||
You can extend SpEL by registering user defined functions that can be called within the
|
||||
expression string. The function is registered with the `StandardEvaluationContext` using
|
||||
the method.
|
||||
expression string. The function is registered through the `EvaluationContext`.
|
||||
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
public void registerFunction(String name, Method m)
|
||||
Method method = ...;
|
||||
|
||||
SimpleEvaluationContext context = new SimpleEvaluationContext();
|
||||
context.setVariable("myFunction", method);
|
||||
----
|
||||
|
||||
A reference to a Java Method provides the implementation of the function. For example, a
|
||||
utility method to reverse a string is shown below.
|
||||
For example, given a utility method to reverse a string is shown below:
|
||||
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
@@ -1042,16 +1022,15 @@ utility method to reverse a string is shown below.
|
||||
}
|
||||
----
|
||||
|
||||
This method is then registered with the evaluation context and can be used within an
|
||||
expression string.
|
||||
The above method can then be registered and used as follows:
|
||||
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
ExpressionParser parser = new SpelExpressionParser();
|
||||
StandardEvaluationContext context = new StandardEvaluationContext();
|
||||
SimpleEvaluationContext context = new SimpleEvaluationContext();
|
||||
|
||||
context.registerFunction("reverseString",
|
||||
context.setVariable("reverseString",
|
||||
StringUtils.class.getDeclaredMethod("reverseString", String.class));
|
||||
|
||||
String helloWorldReversed = parser.parseExpression(
|
||||
@@ -1062,6 +1041,7 @@ expression string.
|
||||
|
||||
[[expressions-bean-references]]
|
||||
=== Bean references
|
||||
|
||||
If the evaluation context has been configured with a bean resolver it is possible to
|
||||
lookup beans from an expression using the (@) symbol.
|
||||
|
||||
@@ -1092,6 +1072,7 @@ To access a factory bean itself, the bean name should instead be prefixed with a
|
||||
|
||||
[[expressions-operator-ternary]]
|
||||
=== Ternary Operator (If-Then-Else)
|
||||
|
||||
You can use the ternary operator for performing if-then-else conditional logic inside
|
||||
the expression. A minimal example is:
|
||||
|
||||
@@ -1126,6 +1107,7 @@ ternary operator.
|
||||
|
||||
[[expressions-operator-elvis]]
|
||||
=== The Elvis Operator
|
||||
|
||||
The Elvis operator is a shortening of the ternary operator syntax and is used in the
|
||||
http://www.groovy-lang.org/operators.html#_elvis_operator[Groovy] language.
|
||||
With the ternary operator syntax you usually have to repeat a variable twice, for
|
||||
@@ -1158,15 +1140,15 @@ Here is a more complex example.
|
||||
ExpressionParser parser = new SpelExpressionParser();
|
||||
|
||||
Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
|
||||
StandardEvaluationContext context = new StandardEvaluationContext(tesla);
|
||||
SimpleEvaluationContext context = new SimpleEvaluationContext();
|
||||
|
||||
String name = parser.parseExpression("Name?:'Elvis Presley'").getValue(context, String.class);
|
||||
String name = parser.parseExpression("Name?:'Elvis Presley'").getValue(context, tesla, String.class);
|
||||
|
||||
System.out.println(name); // Nikola Tesla
|
||||
|
||||
tesla.setName(null);
|
||||
|
||||
name = parser.parseExpression("Name?:'Elvis Presley'").getValue(context, String.class);
|
||||
name = parser.parseExpression("Name?:'Elvis Presley'").getValue(context, tesla, String.class);
|
||||
|
||||
System.out.println(name); // Elvis Presley
|
||||
----
|
||||
@@ -1175,6 +1157,7 @@ Here is a more complex example.
|
||||
|
||||
[[expressions-operator-safe-navigation]]
|
||||
=== Safe Navigation operator
|
||||
|
||||
The Safe Navigation operator is used to avoid a `NullPointerException` and comes from
|
||||
the http://www.groovy-lang.org/operators.html#_safe_navigation_operator[Groovy]
|
||||
language. Typically when you have a reference to an object you might need to verify that
|
||||
@@ -1189,14 +1172,14 @@ safe navigation operator will simply return null instead of throwing an exceptio
|
||||
Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
|
||||
tesla.setPlaceOfBirth(new PlaceOfBirth("Smiljan"));
|
||||
|
||||
StandardEvaluationContext context = new StandardEvaluationContext(tesla);
|
||||
SimpleEvaluationContext context = new SimpleEvaluationContext();
|
||||
|
||||
String city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, String.class);
|
||||
String city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, tesla, String.class);
|
||||
System.out.println(city); // Smiljan
|
||||
|
||||
tesla.setPlaceOfBirth(null);
|
||||
|
||||
city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, String.class);
|
||||
city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, tesla, String.class);
|
||||
|
||||
System.out.println(city); // null - does not throw NullPointerException!!!
|
||||
----
|
||||
@@ -1219,6 +1202,7 @@ This will inject a system property `pop3.port` if it is defined or 25 if not.
|
||||
|
||||
[[expressions-collection-selection]]
|
||||
=== Collection Selection
|
||||
|
||||
Selection is a powerful expression language feature that allows you to transform some
|
||||
source collection into another by selecting from its entries.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user