티스토리 툴바

   고흐는 자살한 미치광이...?  
Front Page
Tag | Location | Media | Guestbook | Admin   
 
Spring 3.0 - Expression Language Support
One of the new features in Spring 3.0 is the Spring Expression Language (Spring EL or SpEL).
While evaluation Spring 3.0 I was also checking out the SpEL capabilities, in this blog entry I'll try to cover some of the more interesting, and less obvious, features and aspects of the SpEL.

The Basics
In its basics SpEL is yet another Expression Language, similar to Unified EL, it supports expressions (no control statements in the language) mainly used to access bean properties, the Spring Expression Language can be used as part of the Spring bean factory configuration (XML or annotation based) but can also be evaluated directly by the application code - meaning we can read and evaluate expressions at runtime. Here is the most basic example of SpEL used in XML factory bean:

<!-- Classic - Simple bean with random value -->
<bean id="randomNumber" class="java.lang.Math" factory-method="random"/>
<bean id="classicBean" class="com.jroller.blogs.eyallupu.MyBean" p:random-ref="randomNumber"/>


<!-- SpEL - Getting the value of the Random bean -->
<bean id="elBean" class="com.jroller.blogs.eyallupu.MyBean" p:random="#{randomNumber}"/>

In the sample above we have the 'classic' section which is using the old standard XML configuration to create two beans, the 'randomNumber' bean and the 'classicBean' bean. The reference to the randomNumber is done using the "p:randon-ref" attribute. In the SpEL section of the example the 'elBean' uses the '#{randomNumber}' expression to reference to 'randomNumber' bean so both 'classicBean' and 'elBean' share the same random value. Beside a first look of the SpEL syntax there is no much use for the expressoin languagae in the example above, we only replaced the 'randomNumber' bean reference with the '#{randomNumber}' expression and we don't gain much out of it. But consider the following example, let's assume that MyBean code is as follows:

public class MyBean implements BeanNameAware{

  private double random = Math.random(); //(1)

  private String beanName;

  public double getRandom() {
    return random;
  }

  public void setRandom(double random) { //(2)
    this.random = random;
  }

  ...
}

The 'random' property value can be set either using the instance variable initializer (1) or using its setter (2). Looking again at the previous example it is obvious that it can easily break - if, in the future, someone decide not to use the classicBean's random property setter but to stick with the auto initialized value of the field then value of elBean's random property will not be identical to the one of the classicBean. SpEL is a great way to easily access the actual value of the 'random' property of the 'classicBean':

<!-- Classic - Simple bean with random value which is not being set from the setter-->
<bean id="classicBean" class="com.jroller.blogs.eyallupu.MyBean"/>

<!-- EL - Getting the value of the Random bean -->
<bean id="elBean" class="com.jroller.blogs.eyallupu.MyBean" p:random="#{classicBean.random}"/>

SpEL Extensions

The two examples above illustrated the very basics of SpEL, in first look it seems to be very similar to Unified EL and in practice it is but is has some interesting features, in this section I want to describe some of these features.

Types

SpEL can access instances of java.lang.Class using the T operator (T stands for Type), for example:

T(java.util.Math)
T(Integer)            //For classes in the java.lang package there is no need to specify the package

Below are some samples using the T operator:

Static Method Invocation and Static Members access

If we can access the java.lang.Class object we would like to access static members - methods and constants - too. The two examples in the box bellow illustrate static methods invocations. I invoke the Math.random() method and the String.format() method (remember that the signature of the String.format() method includes a string argument and a varargs - from the example we see that SpEL supports method invocation using simple and varargs arguments):

<bean id="elBean" class="com.jroller.blogs.eyallupu.MyBean" p:random="#{T(java.util.Math).random()}"/>

<bean id="elBean2" class="...." p:str="#{T(String).format('Hello %s', 'world')}" //Notice that strings are enclosed with a single

The following example illustrates accessing a static field, it gets the value of the Double.MAX_VALUE static field:

<bean id="elBean" class="com.jroller.blogs.eyallupu.MyBean" p:random="#{T(Double).MAX_VALUE}"/>

Instanceof

If we have references to types we can also try and validate if a SpEL expression is of a specific type - this is done using the instanceof operator:

<bean id="elBean" class="..." p:objectProp="A string" />

<!-- EL - instanceof -->
<bean id="elBean2" class="..." p:strProp="#{elBean.objectProp instanceof T(String) ? 'yes' : 'no'}" />

The sample above illustrates access to another bean's property (elBean.objectProp) and invoking the 'instanceof' operator on its value. If the value is a String the expression returns 'yes' otherwise 'no'.

Constructors

Another thing we can do with types (but there is no need for the T operator) is to create new instances, this can be done using the new operator:

<bean id="elBean3" class="..." p:strProp="#{new java.io.File('/tmp/a.a').exists()}" />

The sample above illustrates the new operator but is also illustrates the introduction of some logic into the process of setting value to the 'strProp'. I set the strProp value to 'true' if a specific file exists or to false otherwise, this is done by using the java.io.File(String) constructor with '/tmp/a.a' as a file path and by invoking the exists() method on the newly created File object. Notice that SpEL automatically does the conversion from boolean to string.

Collections - Selections and Projections

SpEL supports collections selections and projections. Using selection we can create a new collection containing a subset of a source collection, the syntax of a selection operator is ?[selection-expression] and to invoke it on a specific collection the following syntax is used: collection-name.?[selection-expression] (notice that a collection can also be a map - more in that below), let's assume that we have a bean which is a list of car manufacturers:

<util:list id="automakers">
  <value>Acura</value>
  <value>Audi</value>
  <value>BMW</value>
  <value>Buick</value>
  <value>Lexus</value>
  <value>Mazda</value>
  <value>Mercedes-Benz USA</value>
  <value>Mitsubishi</value>
  <value>Suzuki</value>
  <value>Toyota</value>
  <value>Volvo</value>
</util:list>

If we would like to obtain a new collection which includes only manufacturers which their name starts with 'M' the following selection will do the work: #{automakers.?[startsWith('M')]} for example:

<util:map id="beanName" value-type="java.lang.Object" key-type="java.lang.String">
   <entry key="starts-with-M" value="#{automakers.?[startsWith('M')]}"/>
</util:map>

This will create the collection: [Mazda, Mercedes-Benz USA, Mitsubishi], if we would like to find only the first name which starts with 'M' we could use the following expression: #{automakers.^[startsWith('M')]} and to find the last one we would substitute the ^ with $. As mentioned before selections also work for Maps, we just have to remember that the member of a map is Map.Entry and to build our selection according to that:

<util:map id="numbersMap" value-type="java.lang.Integer" key-type="java.lang.String">
   <entry key="one" value="1"/>
   <entry key="two" value="2"/>
   <entry key="three" value="3"/>
   <entry key="four" value="4"/>
   <entry key="five" value="5"/>
</util:map>

If we would like to create a new subset map containing the entries 'one' and 'two' the follwoing selection expression will do the work:
numbersMap.?[key=='one' or key=='two']


notice that since the source type was a map the selection output will be a map as well.

A projection creates new collection (or map) out of the results of an expression evaluated on the source collection elements (the source cannot be a set). The syntax for creating a projection is collection-name.![expression-on-elements] (Notice that I use ! and not ? as in the selection). For example the expression #{automakers.![length()]} creates a new collection containing the lengths of the auto maker names ([5, 4, 3, 5, 5, 5, 17, 10, 6, 6, 5]). Of course this could be more meaningful in a real life scenario.

Regular expressions

Last one on this blog entry is regular expressions, SpEL supports regular expressions using the matches operator, this is a relational operator returning true or false. Here is an example:

<util:map id="regExpsSamples" value-type="java.lang.Object" key-type="java.lang.String">
   <entry key="# {'a string' matches 'a.*'}" value="#{'a string' matches 'b.*'}"/>
</util:map>

We can use any regular expression as we would like, for example I could use the '[Mm].*' expression to create the selection illustrated above.



BLOG main image
 Notice
 Category
분류 전체보기 (51)
나의희망 (2)
Spring framework (3)
Database (14)
Linux (9)
Python (0)
VI (12)
Java (2)
Ajax (0)
SOAP (1)
ETC (3)
iBATIS (2)
Jboss (3)
Eclipse (0)
 TAGS
 Calendar
«   2012/01   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        
 Recent Entries
Spring 3.0 - Expression Language Support
Sample XSLT transformation (2)
Spring Web Application Context Visibility (2)
Spring2.5 애노테이션 기반 설정
grep 같은 비슷한 윈도우 Window 명령어 (2)
JSTL 에서 Map 읽기 (4)
ERWin 에서 Logical 이름을 Comment(주석).. (3)
Oracle 시간차 구하기...(2) (3)
Error - "Host not allowed to connect to.. (1)
Can't load Perl file: C:/xampp/apache/co.. (2)
 Recent Comments
확장자를 가진 텍스..
Air yeezy - 17:29
확장자를 가진 텍스..
Air yeezy - 17:20
확장자를 가진 텍스..
Air yeezy - 17:20
확장자를 가진 텍스..
Air yeezy - 17:20
확장자를 가진 텍스..
Air yeezy - 17:20
확장자를 가진 텍스..
Air yeezy - 17:20
확장자를 가진 텍스..
Air yeezy - 17:20
확장자를 가진 텍스..
Air yeezy - 17:20
팝업된 화면의 Code..
Air yeezy - 17:17
팝업된 화면의 Code..
Air yeezy - 17:17
 Recent Trackbacks
database-empire.com..
database-empire.com
database empire for..
database empire
database-empire.com..
database-empire.com
buy databases expense
buy databases
cheap databases exp..
cheap databases
csv databases little
csv databases
cheap databases tone
cheap databases
buy databases speed
buy databases
database empire ask
database empire
database empire tell
database empire
 Archive
2009/10
2009/09
2009/08
2009/07
2009/02
 Link Site
 Visitor Statistics
Total : 16,747
Today : 7
Yesterday : 12
rss