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); 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 + This would typically be done within a call to + SetValue but can also be done inside a call to + GetValue Inventor 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 < Constructors Constructors 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