From f917ba89d6b77f3b152f7aa40aec5fee2f523a5a Mon Sep 17 00:00:00 2001
From: Mark Pollack
Date: Wed, 8 Apr 2009 03:37:28 +0000
Subject: [PATCH] Spring Expression Language docs
---
.../src/expressions.xml | 275 ++++++++++++++++--
1 file changed, 255 insertions(+), 20 deletions(-)
diff --git a/spring-framework-reference/src/expressions.xml b/spring-framework-reference/src/expressions.xml
index 69d57fc2bc2..baca2051868 100644
--- a/spring-framework-reference/src/expressions.xml
+++ b/spring-framework-reference/src/expressions.xml
@@ -239,18 +239,18 @@ boolean isEqual = exp.getValue(context, Boolean.class); // evaluates to true
registerFunction. The use of variables and
functions are described in the language reference sections Variables and Functions.
+ linkend="expressions-ref-functions">Functions. The
+ StandardEvaluationContext is also where you can
+ register custom ConstructorResolvers,
+ MethodResolvers, and
+ PropertyAccessors to extend how SpEL evaluates
+ expressions. Please refer to the JavaDoc of these classes for more
+ details.
Type Conversion
- The StandardEvaluationContext uses an instance of
- org.springframework.expression.TypeConverter. A
- simple implementation of this interface,
- StandardTypeConverter, that converts basic
- types, primitive values, booleans and characters is used but will be
- replaced with an updated type conversion framework that is to be
- included as part of Spring 3.0
+ TODO
@@ -276,7 +276,8 @@ boolean isEqual = exp.getValue(context, Boolean.class); // evaluates to true
The variable 'systemProperties' is predefined, so you can use it
- in your expressions as shown below.
+ in your expressions as shown below. Note that you do not have to prefix
+ the predefined variable with the '#' symbol in this context.
<bean id="taxCalculator" class="org.spring.samples.TaxCalculator">
<property name="defaultLocale" value="#{ systemProperties['user.region'] }"/>
@@ -376,7 +377,7 @@ boolean isEqual = exp.getValue(context, Boolean.class); // evaluates to true
- Case insensitivty is allowed for the first letter of proprety
+ Case insensitivity is allowed for the first letter of property
names. The contents of arrays and lists are obtained using square
bracket notation.
@@ -606,8 +607,9 @@ int minusTwentyOne = parser.parseExpression("1+2-3*8").getValue(Integer.class);
AssignmentSetting 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
+ This would typically be done within a call to
+ SetValue but can also be done inside a call to
+ GetValueInventor inventor = new Inventor();
StandardEvaluationContext inventorContext = new StandardEvaluationContext();
@@ -627,7 +629,7 @@ String aleks = parser.parseExpression("Name = 'Alexandar Seovic'").getValue(inve
Types
- The specic 'T' operator can be used to specify an instance of
+ 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
@@ -642,7 +644,7 @@ boolean isEqual = parser.parseExpression("T(java.math.RoundingMode).CEILING <
ConstructorsConstructors can be invoked using the new operator. The fully
- qualified classname should be used for all but the primitive type and
+ qualified class name should be used for all but the primitive type and
String (where int, float, etc, can be used).Inventor einstein =
@@ -663,6 +665,8 @@ parser.parseExpression("Members.add(new org.spring.samples.spel.inventor.Invento
Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("newName", "Mike Tesla");
+
+
context.setRootObject(tesla);
parser.parseExpression("Name = #newName").getValue(context);
@@ -670,16 +674,65 @@ parser.parseExpression("Name = #newName").getValue(context);
System.out.println(tesla.getName()) // "Mike Tesla"
- The #this and #root variables
+ The #this variables
- blah blah
+ The variable #this is always defined and refers to the root
+ object that is currently being evaluated.
+
+ // create an array of integers
+List<Integer> primes = new ArrayList<Integer>();
+primes.addAll(Arrays.asList(2,3,5,7,11,13,17));
+
+// create parser and set variable 'primes' as the array of integers
+ExpressionParser parser = new SpelAntlrExpressionParser();
+StandardEvaluationContext context = new StandardEvaluationContext();
+context.setVariable("primes",primes);
+
+// all prime numbers > 10 from the list (using selection ?{...})
+List<Integer> primesGreaterThanTen = (List<Integer>) parser.parseExpression("#primes.?{#this>10}").getValue(context);
+
+//evaluates to [11, 13, 17]Functions
- blah blah
+ 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
+
+ public void registerFunction(String name, Method m)
+
+ A reference to a Java Method provides the implementation of the
+ function. For example, a utility method to reverse a string is shown
+ below.
+
+ public abstract class StringUtils {
+
+ public static String reverseString(String input) {
+ StringBuilder backwards = new StringBuilder();
+ for (int i = 0; i < input.length(); i++) {
+ backwards.append(input.charAt(input.length() - 1 - i));
+ }
+ return backwards.toString();
+ }
+}
+
+ This method is then registered with the evaluation context and can
+ be used within an expression string
+
+ used in To register this method with the evaluation context and
+ used in an expression string
+
+ ExpressionParser parser = new SpelAntlrExpressionParser();
+StandardEvaluationContext context = new StandardEvaluationContext();
+
+context.registerFunction("reverseString",
+ StringUtils.class.getDeclaredMethod("reverseString", new Class[] { String.class }));
+
+String helloWorldReversed = parser.parseExpression("#reverseString('hello')").getValue(context, String.class);
@@ -722,13 +775,195 @@ String queryResultString = parser.parseExpression(expression).getValue(societyCo
Expression templating
- blah blah
+ Expression templates allow a mixing of literal text with one or
+ more evaluation blocks. Each evaluation block is delimited with a prefix
+ and suffix characters that you can define, a common choice is to use
+ ${} as the delimiters. For example,
+
+ String randomPhrase =
+ parser.parseExpression("random number is ${T(java.lang.Math).random()}", new TemplatedParserContext()).getValue(String.class);
+
+// evaluates to "random number is 0.7038186818312008"
+
+ The string is evaluated by concatenating the literal text 'random
+ number is' with the result of evaluating the expression inside the ${}
+ delimiter, in this case the result of calling that random() method. The
+ second argument to the method parseExpression() of
+ the type ParserContext. The
+ ParserContext interface is used to
+ influence how the expression is parsed in order to support the
+ expression templating functionality. The definition of
+ TemplatedParserContext is shown below
+
+ public class TemplatedParserContext implements ParserContext {
+
+ public String getExpressionPrefix() {
+ return "${";
+ }
+
+ public String getExpressionSuffix() {
+ return "}";
+ }
+
+ public boolean isTemplate() {
+ return true;
+ }
+}Classes used in the examples
-
+ Inventor.java
+
+ package org.spring.samples.spel.inventor;
+
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+public class Inventor {
+
+ private String name;
+ private String nationality;
+ private String[] inventions;
+ private Date birthdate;
+ private PlaceOfBirth placeOfBirth;
+
+
+ public Inventor(String name, String nationality)
+ {
+ GregorianCalendar c= new GregorianCalendar();
+ this.name = name;
+ this.nationality = nationality;
+ this.birthdate = c.getTime();
+ }
+ public Inventor(String name, Date birthdate, String nationality) {
+ this.name = name;
+ this.nationality = nationality;
+ this.birthdate = birthdate;
+ }
+
+ public Inventor() {
+ }
+
+ public String getName() {
+ return name;
+ }
+ public void setName(String name) {
+ this.name = name;
+ }
+ public String getNationality() {
+ return nationality;
+ }
+ public void setNationality(String nationality) {
+ this.nationality = nationality;
+ }
+ public Date getBirthdate() {
+ return birthdate;
+ }
+ public void setBirthdate(Date birthdate) {
+ this.birthdate = birthdate;
+ }
+ public PlaceOfBirth getPlaceOfBirth() {
+ return placeOfBirth;
+ }
+ public void setPlaceOfBirth(PlaceOfBirth placeOfBirth) {
+ this.placeOfBirth = placeOfBirth;
+ }
+ public void setInventions(String[] inventions) {
+ this.inventions = inventions;
+ }
+ public String[] getInventions() {
+ return inventions;
+ }
+}
+
+
+ PlaceOfBirth.java
+
+ package org.spring.samples.spel.inventor;
+
+public class PlaceOfBirth {
+
+ private String city;
+ private String country;
+
+ public PlaceOfBirth(String city) {
+ this.city=city;
+ }
+ public PlaceOfBirth(String city, String country)
+ {
+ this(city);
+ this.country = country;
+ }
+
+
+ public String getCity() {
+ return city;
+ }
+ public void setCity(String s) {
+ this.city = s;
+ }
+ public String getCountry() {
+ return country;
+ }
+ public void setCountry(String country) {
+ this.country = country;
+ }
+
+
+
+}
+
+
+ Society.java
+
+ package org.spring.samples.spel.inventor;
+
+import java.util.*;
+
+public class Society {
+
+ private String name;
+
+ public static String Advisors = "advisors";
+ public static String President = "president";
+
+ private List<Inventor> members = new ArrayList<Inventor>();
+ private Map officers = new HashMap();
+
+ public List getMembers() {
+ return members;
+ }
+
+ public Map getOfficers() {
+ return officers;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public boolean isMember(String name)
+ {
+ boolean found = false;
+ for (Inventor inventor : members) {
+ if (inventor.getName().equals(name))
+ {
+ found = true;
+ break;
+ }
+ }
+ return found;
+ }
+
+
+}
+
\ No newline at end of file