Struts 2 - Using OGNL To Filter A Java Collection
Introduction
I recently was creating a web application using the Struts 2 Java web application framework. On one of my view pages I needed to display the objects stored in a Java collection that was on the Struts value stack. In addition to displaying all the objects in the collection, I also needed to display just some of the objects from the collection based on certain criteria. For example display only those objects stored in the collection where the amount field equals 100.
At first I thought I'd have to create separate collections in my Struts 2 action support class: one collection that stored all the objects and another collection that stored only those objects whose amount field equals 100. But fortunately, I happen to run across section 6.7 in the Struts 2 In Action book (Manning publishing, 2008) where the authors briefly mention using OGNL to filter a collection when using the Struts 2 iterator tag.
Since I wasn't familiar with this capability and there did not seem to be much information easily available about filtering a collection using an OGNL expression in Struts 2, I thought writing up a blog article might be helpful.
Object-Graph Navigation Language (OGNL)
Struts 2 uses OGNL to provide many of the features (data conversion, binding) of the framework. OGNL is a powerful language that has many additional capabilities. Consult the reference below to learn more about it.
Filter A Collection
One of the capabilities that OGNL provides to the Struts 2 framework is the ability to filter a collection. After applying the filter expression, you'll have a new collection that you can display. An example might help explain (view the example online or download the example code - Eclipse Dynamic Web Project | MyEclipse Web Project). Let's say I need to create a web application that displays all the iPod sales at our store. The information displayed needs to include the salesperson, the type of iPod sold, and the amount of the sale.
To store a sale, I use the Sale class which has fields for salesPerson, salesItem, and salesAmount. For each iPod sale, I create a new Sale object and then store that Sale object in a Java ArrayList named sales. In the Java Server Page (JSP), I can use the Struts 2 iterator tag to loop over and display each Sale object stored in the sales collection. For example:
<table width="450" cellpadding="5" border="1">
<tr>
<th width="40">Row Number</th>
<th width="100">Salesperson</th>
<th width="210">Sale Item</th>
<th width="80">Sale Amount</th>
</tr>
<s:iterator value="sales" status="itStatus">
<tr>
<td><s:property value="#itStatus.count" /></td>
<td><s:property value="salesPerson" /></td>
<td><s:property value="saleItem" /></td>
<td><s:property value="saleAmount" /></td>
</tr>
</s:iterator>
</table>
The above code should be pretty familiar to Struts 2 web application developers. But let's say I also need to display just the sales made by Steve. Rather then create an entirely separate collection that just contains Sale objects where the salesPerson's equals "Steve" in my Struts 2 ActionSupport class I can use an OGNL expression to filter the original collection that contains all the Sale objects so that only those Sale objects with a salesPerson field value of "Steve" are displayed. Here's the code:
<table width="450" cellpadding="5" border="1">
<tr>
<th width="40">Row Number</th>
<th width="100">Salesperson</th>
<th width="210">Sale Item</th>
<th width="80">Sale Amount</th>
</tr>
<%--Note the use of the OGNL filter expression. Only the Sale
objects in the collection that have a salesPerson value of Steve
will be displayed --%>
<s:iterator value="sales.{? #this.salesPerson == 'Steve'}" status="itStatus">
<tr>
<td><s:property value="#itStatus.count" /></td>
<td><s:property value="salesPerson" /></td>
<td><s:property value="saleItem" /></td>
<td><s:property value="saleAmount" /></td>
</tr>
</s:iterator>
</table>
Note the value attribute now has sales.{? #this.salesPerson == 'Steve'}. The part inside the { } is an OGNL expression that means create a new collection by copying only those Sale objects with a salesPerson value of 'Steve' from the sales collection. The Struts 2 iterator tag will then use this new collection.
You can even create more complicated expressions by using the boolean operators && (and) or || (or). For example, let's say I need to also display the iPod sales done by Sue and that had a sale amount greater than 150. Here's the code:
<table width="450" cellpadding="5" border="1">
<tr>
<th width="40">Row Number</th>
<th width="100">Salesperson</th>
<th width="210">Sale Item</th>
<th width="80">Sale Amount</th>
</tr>
<%--Note the use of the OGNL filter expression. Only the Sale
objects in the collection that have a saleAmount greater than 150
and a salesPerson value of Sue will be displayed --%>
<s:iterator value="sales.{?#this.saleAmount > 150 && #this.salesPerson == 'Sue' }" status="itStatus">
<tr>
<td><s:property value="#itStatus.count" /></td>
<td><s:property value="salesPerson" /></td>
<td><s:property value="saleItem" /></td>
<td><s:property value="saleAmount" /></td>
</tr>
</s:iterator>
</table>
Note the use of the && (and) operator to combine two expressions. The new collection will contain only those Sale objects from the sales collection where the salesPerson field value is 'Sue' and the saleAmount field value is greater than 150.
Summary
When you just need to display part of a collection on your view page, using an OGNL expression to filter the original collection can be useful.
References
- Struts 2 Documentation, OGNL
- Struts 2 In Action, Manning Publishing, 2008, Section 6.7
- OGNL Language Reference, Selecting From Collections
- Demo of Using An OGNL Expression to Filter A Collection
- Example Code - Eclipse Dynamic Web Project, Using An OGNL Expression to Filter A Collection
- Example Code - MyEclipse Web Project, Using An OGNL Expression to Filter A Collection
There are no comments for this entry.
[Add Comment]