Wiring beans
61Wiring with expressions
<property name="chosenCity" value="#{cities['Dallas']}"/>
Another use of the [] operator is to retrieve a value from a java.util.Properties collection. For example, suppose that you were to load a properties configuration file into Spring using the <util:properties> element as follows:
<util:properties id="settings"
location="classpath:settings.properties"/>
Here the settings bean will be a java.util.Properties that contains all of the entries in the file named settings.properties. With SpEL, you can access a property from that file in the same way you access a member of a Map. For example, the follow-ing use of SpEL reads a property whose name is twitter.accessToken from the settings bean:
<property name="accessToken" value="#{settings['twitter.accessToken']}"/>
In addition to reading properties from a <util:properties>-declared collection, Spring makes two special selections of properties available to SpEL: system-Environment and systemProperties.
systemEnvironment contains all of the environment variables on the machine run-ning the application. It’s just a java.util.Properties collection, so the square braces can be used to access its members by their key. For example, on my MacOS X machine, I can inject the user’s home directory path into a bean property like this:
<property name="homePath" value="#{systemEnvironment['HOME']}"/>
Meanwhile, systemProperties contains all of the properties that were set in Java as the application started (typically using the -D argument). Therefore, if the JVM were started with -Dapplication.home=/etc/myapp, then you could wire that value into the homePath property with the following SpEL incantation:
<property name="homePath" value="#{systemProperties['application.home']}"/>
Although it doesn’t have much to do with working with collections, it’s worth noting that the [] operator can also be used on String values to retrieve a single character by its index within the String. For example, the following expression will evaluate to "s":
'This is a test'[3]
Accessing individual members of a collection is handy. But with SpEL, we can also select members of a collection that meet certain criteria. Let’s give collection selection a try.
SELECTING COLLECTION MEMBERS
Let’s say that you want to narrow the list of cities down to only those whose population is greater than 100,000. One way to do this is to wire the entire cities bean into a property and place the burden of sifting out the smaller cities on the receiving bean.
But with SpEL, it’s a simple matter of using a selection operator (.?[]) when doing the wiring:
<property name="bigCities" value="#{cities.?[population gt 100000]}"/>
62 CHAPTER 2 Wiring beans
The selection operator will create a new collection whose members include only those members from the original collection that meet the criteria expressed between the square braces. In this case, the bigCities property will be wired with a list of City objects whose population property exceeds 100,000.
SpEL also offers two other selection operators, .^[] and .$[], for selecting the first and last matching items (respectively) from a collection. For example, to select the first big city from cities:
<property name="aBigCity" value="#{cities.^[population gt 100000]}"/>
No ordering is done on the collection prior to selection, so the City representing Chi-cago would be wired into the aBigCity property. Likewise, the City object represent-ing El Paso could be selected as follows:
<property name="aBigCity" value="#{cities.$[population gt 100000]}"/>
We’ll revisit collection selection in a moment. But first, let’s see how to project proper-ties from a collection into a new collection.
PROJECTING COLLECTIONS
Collection projection involves collecting a particular property from each of the mem-bers of a collection into a new collection. SpEL’s projection operator (.![]) can do exactly that.
For example, suppose that instead of a list of City objects, what you want is just a list of String objects containing the names of the cities. To get a list of just the city names, you could wire a cityNames property like this:
<property name="cityNames" value="#{cities.![name]}"/>
As a result of this expression, the cityNames property will be given a list of Strings, including values such as Chicago, Atlanta, Dallas, and so forth. The name property within the square braces decides what each member of the resulting list will contain.
But projection isn’t limited to projecting a single property. With a slight change to the previous example, you can get a list of city and state names:
<property name="cityNames" value="#{cities.![name + ', ' + state]}"/>
Now the cityNames property will be given a list containing values such as “Chicago, IL”, “Atlanta, GA”, and “Dallas, TX”.
For my final SpEL trick, let me bring collection selection and projection together.
Here’s how you might wire a list of only big city names into the cityNames property:
<property name="cityNames"
value="#{cities.?[population gt 100000].![name + ', ' + state]}"/>
Since the outcome of the selection operation is a new list of City objects, there’s no reason why I can’t use projection on that new collection to get the names of all of the big cities.
This demonstrates that you can assemble simple SpEL expressions into more inter-esting (and more complex) expressions. It’s easy to see how that’s a powerful feature.
63 Summary
But it doesn’t take much of a stretch to realize that it’s also dangerous. SpEL expres-sions are ultimately just Strings that are tricky to test and have no IDE support for syn-tax checking.
I encourage you to use SpEL wherever it can simplify what would otherwise be dif-ficult (or even impossible) wirings. But be careful to not get too carried away with SpEL. Fight the temptation to put too much logic into a SpEL expression.
We’ll see some more SpEL later on and used in ways other than bean wiring. In the next chapter we’ll break SpEL out of XML and use it in annotation-driven wiring. And, as we’ll see in chapter 9, SpEL plays a significant role in the latest version of Spring Security.
2.4 Summary
At the core of the Spring Framework is the Spring container. Spring comes with several implementations of its container, but they all fall into one of two categories.
A BeanFactory is the simplest form of container, providing basic DI and bean-wiring services. But when more advanced framework services are needed, Spring’s ApplicationContext is the container to use.
In this chapter, you’ve seen how to wire beans together within the Spring con-tainer. Wiring is typically performed within a Spring container using an XML file. This XML file contains configuration information for all of the components of an applica-tion, along with information that helps the container perform DI to associate beans with other beans that they depend on.
Now that you know how to wire beans using XML, I’ll show you how to use less XML. In the next chapter, we’ll look at how to take advantage of automatic wiring and annotations to reduce the amount of XML configuration in a Spring application.
64