Expression Evaluation using Spring's Expression Interface - Java-Springs

The following code introduces the SpEL API to evaluate the literal string expression 'Hello World'.

ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'");
String message = (String) exp.getValue();

The value of the message variable is simply 'Hello World'.

The SpEL classes and interfaces you are most likely to use are located in the packages org.spring frame work.expression and its sub packages and spel.support.

The interface Expression Parser is responsible for parsing an expression string. In this example the expression string is a string literal denoted by the surrounding single quotes.The interface Expression is responsible for evaluating the previously defined expression string.There are two exceptions that can be thrown, Parse Exception and EvaluationException when calling 'parser.parseExpression' and 'exp.getValue' respectively.

SpEL supports a wide range of features, such as calling methods, accessing properties, and calling constructors.

As an example of method invocation, we call the 'concat' method on the string literal.

ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'.concat('!')");
String message = (String) exp.getValue();

The value of message is now 'Hello World!'.

As an example of calling a JavaBean property, the String property 'Bytes' can be called as shown below.

ExpressionParser parser = new SpelExpressionParser();
// invokes 'getBytes()'
Expression exp = parser.parseExpression("'Hello World'.bytes");
byte[] bytes = (byte[]) exp.getValue();

SpEL also supports nested properties using standard 'dot' notation, i.e. prop1.prop2.prop3 and the setting of property values

Public fields may also be accessed.

ExpressionParser parser = new SpelExpressionParser();
// invokes 'getBytes().length'
Expression exp = parser.parseExpression("'Hello World'.bytes.length");
int length = (Integer) exp.getValue();

The String's constructor can be called instead of using a string literal.

ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("new String('hello world').toUpperCase()");
String message = exp.getValue(String.class);

Note the use of the generic method public <T> T getValue(Class<T> desiredResultType).Using this method removes the need to cast the value of the expression to the desired result type. An EvaluationException will be thrown if the value cannot be cast to the 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.

// 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");
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:

/ 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);

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 Standard Evaluation Context is relatively expensive to construct and during repeated usage it builds up cached state that enables sub sequent 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 get Value. get Value 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.

As a final introductory example, the use of a boolean operator is shown using the Inventor object in the previous example.

Expression exp = parser.parseExpression("name == 'Nikola Tesla'"); bolean result = exp.getValue(context, Boolean.class); // evaluates to true

The EvaluationContext interface

The interface Evaluation Context is used when evaluating an expression to resolve properties, methods, fields, and to help perform type conversion. The out-of- the-box implementation, Standard Evaluation Context, uses reflection to manipulate the object, caching java. lang. reflect's Method, Field, and Constructor instances for increased performance.

The Standard Evaluation Context is where you may specify the root object to evaluate against via the method set Root Object() 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 Standard Evaluation Context is also where you can register custom Constructor Resolvers, Method Resolvers, and Property Accessors to extend how SpEL evaluates expressions.

Type Conversion

By default SpEL uses the conversion service available in Spring core (org.spring frame work.core. convert.ConversionService). This conversion service comes with many converters built in for common conversions but is also fully extensible so custom conversions between types can be added. Additionally it has the key capability that it is generics aware.

This means that when working with generic types in expressions, SpEL will attempt conversions to maintain type correctness for any objects it encounters.

What does this mean in practice? Suppose assignment, using setValue(), is being used to set a List property.The type of the property is actually List<Boolean>. SpEL will recognize that the elements of the list need to be converted to Boolean before being placed in it. A simple example:

class Simple {
public List<Boolean> booleanList = new ArrayList<Boolean>();
}
Simple simple = new Simple();
simple.booleanList.add(true);
StandardEvaluationContext simpleContext = new StandardEvaluationContext(simple);
// 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");
// b will be false
Boolean b = simple.booleanList.get(0);

All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd DMCA.com Protection Status

Java-Springs Topics