 | Improvement in Ognl 2.7 and above
Jesse has made changes in Ognl available in 2.7 and above that improves performance. Some modifications on the how Ognl is used is required to benifits from the improvements, more information could be found here .
WebWork 2.2.7 and above will take advantages of this improvement done in Ognl. |
Overview
OGNL is the Object Graph Navigation Language - see http://www.ognl.org
for the full documentation of OGNL. In this document we will only show a few examples of OGNL features that co-exist with Webwork. To review basic concepts, refer to OGNL Basics.
Webwork uses a standard naming context to evaluate OGNL expressions. The top level object dealing with OGNL is a map (usually referred as a context map). OGNL has a concept of a root object (in webwork terms, this is the OGNLValueStack). Along with the root, other objects are placed in the context map (referred as in the context) including your session/application/request/attr maps. These objects have nothing to do with the root, they just exist along side it in the context map. So, to access these objects, the # is used telling ognl not to look in the root object, but within the rest of the context
Note that their are other objects in the context map, I'm just referring to a few for this example. Now, your actions instances are placed in the OGNLValueStack so you can refer to your bean properties without the #.
<ww: property value="myBean.myProperty"/>
For sessions,request, and the rest that lie in the context map:
ActionContext.getContext().getSession().put("mySessionPropKey", mySessionObject);
<ww:property value="#session.mySessionPropKey"/> or
<ww:property value="#session['mySessionPropKey']"/> or
<ww:property value="#attr.mySessionPropKey"/>
 | A note about #attr
If a page context is present, #attr will search the page context. else it #attr will search request, session then finally application scope for the attribute. |
Collections (Maps, Lists, Sets)
Dealing with collections(maps, lists, and sets) in webwork comes often, so here are a few examples using the select tag:
Syntax for list: {e1,e2,e3}. This creates a List containing the String "name1", "name2" and "name3". It also selects "name2" as the default value. Notice the use of the Alt Syntax to provide the literal "name2".
<ww:select label="label" name="name" list="{'name1','name2','name3'}" value="%{'name2'}" />
Syntax for map: #{key1:value1,key2:value2}. This creates a map that maps the string "foo" to the string "foovalue" and "bar" to the string "barvalue":
<ww:select label="label" name="name" list="#{'foo':'foovalue', 'bar':'barvalue'}" />
You may need to determine if an element exists in a collection. You can accomplish this with the operations in and not in
<ww:if test="'foo' in {'foo','bar'}">
muhahaha
</ww:if>
<ww:else>
boo
</ww:else>
<ww:if test="'foo' not in {'foo','bar'}">
muhahaha
</ww:if>
<ww:else>
boo
</ww:else>
To select a subset of a collection (called projection), you can use a wildcard within the collection.
- ? - All elements matching the selection logic
- ^ - Only the first element matching the selection logic
- $ - Only the last element matching the selection logic
To obtain a subset of just male relatives from the object person:
person.relatives.{? #this.gender == 'male'}
Lambda Expressions
OGNL supports basic lamba expression syntax enabling you to write simple functions. For example:
For all you math majors who didn't think you would ever see this one again.
Fibonacci: if n==0 return 0; elseif n==1 return 1; else return fib(n-2)+fib(n-1);
fib(0) = 0
fib(1) = 1
fib(11) = 89
 | Useful Information
The lambda expression is everything inside the brackets. The #this variable holds the argument to the expression, which is initially starts at 11. |
<ww:property value="#fib =:[#this==0 ? 0 : #this==1 ? 1 : #fib(#this-2)+#fib(#this-1)], #fib(11)" />
Note that velocity stack is different from ognl stack. Thus if you are using velocity script like this:
#foreach $item in $list ...
Then when you use a tag such as #bodytag(Bean ...), that tag cacnnot access variable $item. This is because $item is within the velocity stack and the bodytag accesses the ognl stack only.
I stuck on this confusion for a while. Hope this can help others.