Spring Expression Language (SpEL) was one of the new features that debuted with Spring 3.0.  Spring 3.0 was released back in December 2009.  So that makes this feature a little less than four years old as of this writing.  Yet, in my informal survey of teams using Spring, I am always a bit surprised at how few applications are taking advantage of this powerful feature today. So in this post, I’d like to provide a quick tutorial on SpEL and highlight a few places I think SpEL can help in your project.

The Syntax

First off, SpEL can be used in both XML and annotation metadata (also known as Spring configuration or wiring).  In either case, the syntax to designate a Spring expression for evaluation at runtime is #{ “SpEL expression string”}.  Here is a simple example of using SpEL in XML to provide default values to an Address bean:

<bean id="officeAddress">
     <property name="street" value="#{'Thomas Lake Drive'}"/>
     <property name="city" value="#{'Eagan'}"/>
     <property name="state" value="#{'MN'}"/>
     <property name="zip" value="#{55121}"/>
 </bean>

Admittedly, there isn’t a lot of reason to use SpEL in this way as providing simple values to the bean’s properties is simpler without SpEL.  However, this simple example is meant to show the syntax and not the purpose of SpEL.

Use the @Value annotation when using SpEL in metadata in the bean class.

public class Address {

  @Value("#{'Thomas Lake Drive'}")
  private String street;
  @Value("#{'Eagan'}")
  private String city;
  @Value("#{'MN'}")
  private String state;
  @Value("#{55121}")
  private int zip;
   // methods left off for brevity
}

This example demonstrates the way SpEL can be used to provide the dependency injection of simple default values by annotation at runtime.  Prior to SpEL, providing simple values (int, double, String, etc.) could be done by XML, but not by annotation.  Admittedly, however even this simple example may seem a little meaningless since one could easily provide default values through simple explicit initialization (like that for street shown below).

public class Address {
  private String street = "Thomas Lake Drive";
   ...
}

So again, the example, while trivial, is meant to show the syntax and not the full purpose of SpEL.

Under the Covers

SpEL is just an expression language – that is a string that must be evaluated for any meaning.  It is evaluated at runtime.  When a SpEL expression is evaluated, it can query and manipulate an object or object graph.  The results of evaluation can be used to dynamically inject values or objects into other beans.  In the examples above, the SpEL strings are evaluated to simple values used to inject into the Address beans, but the power comes with more sophisticated Spring expressions.

Inside of Spring is a collection of classes used to parse and evaluate the Spring Expressions.  A SpELExpression is used to parse a SpEL expression string.  The parseExpression( ) method on the SpELExpressionParser returns a SpELExpression object.  This object can then be used to evaluate the expression with a call to getValue( ).

SpEL API

An EvaluationContext allows objects, variables, functions, etc. to be used in the evaluation of the expression. You can actually use this API in your Java code, not unlike how you might use other expression languages to evaluate strings for value.  Below is a simple example of using the Spring Expression Language API – in code versus metadata.

ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext evalContext = new StandardEvaluationContext();
evalContext.setVariable("myString", "This is it");
Boolean result = (Boolean) parser.parseExpression("#myString.endsWith('it')").getValue(evalContext);

It is much more likely that you will use SpEL in your XML and annotation based metadata (to include Spring Web Flow, Spring Security or other Spring configuration).  When used in Spring configuration, a SpEL ExpressionParser and EvaluationContext are already defined in the container implicitly.  These are used by Spring to evaluate your SpEL expressions in @Value and in XML.

Why use SpEL

Now that you understand a little bit about how SpEL works and where it can be applied, the question remains… “Why use SpEL?” or “Where to use SpEL?”  The answer is to provide dynamic bean wiring (dependency injection) at runtime.  In particular, you can use SpEL in conditional situations to pick the right bean or value to dependency inject based on what is happening and discovered in the application.  The conditionalization could be based on the hardware platform, the operating system, application server hosting the application, the user’s locale, etc.  The examples below should help to provide some cases of how the wiring of your beans can become very dynamic using SpEL.

Some Example SpEL Uses

Simple Bean Dependency Injection

SpeEL allows you to reference an already defined bean and dependency inject it, or one of its properties, into another object.  Perhaps you have a bean that represents an authenticated user as demonstrated in this example below.

<bean id="user">
  <property name="name" value="Jim"/>
  <property name="password" value="test"/>
</bean>

You can then dependency inject the “user” bean or its properties into other beans with SpEL.  Extending this example, perhaps you have a PersonalizationService that needs the user to know how to personalize the UI.  Below is the code to use SpEL to carry out this dependency injection.  It shows how either the user bean itself, or its property (username in this example) can be dependency injected.  Use dot notation to reference either properties or methods of a bean (discussed later) in SpEL.

public class PersonalizationService {
  @Value("#{user}")
  private User user;
  @Value("#{user.name}")
  private String userName;
  ...
}
Environmental Dependency Injection

There are many times when you want to dependency inject a particular bean based on some environmental situation.  Perhaps, for example, you want to dependency inject a Windows driver datasource when running on an x86 server and an alternate driver datasource when running in a Unix environment.  In SpEL, systemProperties is a predefined variable in the implicit EvaluationContext.  Therefore, you can use it to help conditionally wire the appropriate bean or value based on one of the system properties.  Here, the SpEL expression checks the standard Java os.arch property and when it is “x86” , the bean identified by the name winDataSource is dependency injected into the datasource property of the DAO.  Otherwise the unixDataSource bean is dependency injected into the datasource property of the DAO.  [Note: see http://docs.oracle.com/javase/tutorial/essential/environment/sysprop.html for the predefined Java system properties – of course you can always define your own custom system property.]

public class MyDao {
  @Value("#{systemProperties['os.arch'].equals('x86') ? winDataSource : unixDataSource}")
  private DataSource datasource;
  ...
 }

In particular, this use (environmental-conditionalization) of SpEL can be quite handy when moving across dev, test, stage, production environments and the dependency injection of particular resources is system dependent.  Instead of writing code to determine how to wire objects in various environments, let SpEL figure it out based on system properties.

Method Factory Wiring

If you are familiar with the abstract factory or factory method pattern, you know are times when the construction of an object takes considerable effort and/or information to create.  These factory patterns help to coalesce object creation into another method/class.  With SpEL, bean methods in the Spring container can serve as factories to dynamically provide objects or values for dependency injection at runtime.  The methods may use any number of factors and conditions to determine what object or value to provide to Spring for injection.  Shown below, a FileService bean with a createFile( ) method is called to produce a java.io.File object.  The method could create the File with a filename based on runtime factors such as the current date/time and geo-location of the system – things that could not be provided in any static metadata.

@Component("fileService") 
public class FileService {
  public File createFile(){
    String filename = // produce file name based on runtime determined 
                      // date/time, geolocation, etc.
    return new File("filename");
  }
}

With the File factory available as a bean, you can then use SpEL to call on the factory method at runtime to inject a File object into another object.

public class FileNeeder {
  @Value("#{fileService.createFile()}")
  private File file;
  ...
}

Note the use of dot notation again to call on the method of another bean.

Static Method Wiring

Class methods (static methods) can also be used in a fashion similar to the bean methods of the last example.  For example, SpEL allows the use of any Java class and static method like random( ) on the java.lang.Math class.  I found this can come in very handy when your application operates on fluctuating values (exchange rage, instrumentation measurement reading, die role, etc.) and you need to mimic this behavior with test/mock beans.  Below, Math’s static random method is used with SpEL to generate a percentage value representing some fluctuating power level.  The “T” in the expression indicates type.  Since Math is in the java.lang package, it does not need to be qualified, but other types can be called on so long as they are fully qualified.

public class SystemMonitor {
  @Value("#{ T(Math).random()}")
  private double powerLevel;
  ...
}
Collection Selections and Projections

SpEL comes with some interesting operators that one may find in languages like Groovy, but not in Java.  Two of them – selection and projection – operate on collections to filter and transform them respectively.  To demonstrate, assume you had a collection of Customer beans.  The Customer objects have a name and date of birth property among potentially other properties.

public class Customer {
  private String name;
  private Calendar dateOfBirth;
  ...
}

Also assume another bean provides the date of current legal age.  In fact, to reemphasize the use of SpEL and factory methods above, I’ll use SpEL to initialize the legal age in a LegalServices bean.

@Component("legalServices")
public class LegalServices {
  @Value("#{legalServices.initLegalLimit()}")
  private Calendar legalLimit;

  public void initLegalLimit() {
    legalLimit = Calendar.getInstance();
    legalLimit.set(Calendar.YEAR, legalLimit.get(Calendar.YEAR) - 21);
  }

  public Calendar getLegalLimit() {
    return legalLimit;
  }
}

SpEL’s selection operator is “.?” and it allows you to filter the collection and return a new collection containing a subset of the original elements.  So, given a list of customers (here called “customers”) and the LegalServices bean, you can use SpEL to filter the list of customers for those of legal age.

<property name="ofAgeCustomers" value="#{customers.?[dateOfBirth.before(legalServices.legalLimit)]}" />

In this case, SpEL gets the dateOfBirth property from each Customer in the “customers” list and if it is a Calendar object before the legalLimit (out of the LegalServices), it adds the Customer object to the new sub-list (in this case called ofAgeCustomers).

You can also use “.^” in place of “.?” to select the first member of the list meeting the criteria or use “.$” to select the last element in the collection to meet the criteria. 

The projection operator is “.!” and it allows you to transform a list like the customer list into some other list.  Suppose you wanted the name Strings of the Customer objects.  In that case, use the projection operator to transform the list of Customers into a list of name Strings.

<property name="names" value="#{customers.![name]}" />
Wrap Up

Hopefully, the next time you are wiring together objects and values in Spring you’ll explore the possibilities of how Spring Expression Language might help.