The tag syntax in WebWork is extremely easy to understand. To quickly get started, all you need to know is that all attributes are applied as Strings initially. They are then parsed for the syntax %{ ... }, and anything in between the braces is evaluated against the value stack.
Note | ||
---|---|---|
| ||
The tag syntax was not always this easy – if you are upgrading from WebWork 2.1.7 or previous versions, you may wish to read about the Alt Syntax. |
Like most things in life, it turns out that this isn't quite that simple. Specifically, there are actually three rules to be aware of:
- All String attribute types are parsed for the %{ ... } characters.
- All non-String attribute types are not parsed, but instead evaluated directly as an OGNL expression
- The exception to rule #2 is that if the non-String attribute starts with %{ and ends with }, those characters are cut off before evaluating the expression.
The best way to understand these rules is by looking at some examples.
Note |
---|
We recognize that these rules can be confusing. Generally, you should not need to know them at all, as 99.9% of the time everything will "just work". However, as we see in the examples, there are some tricky situations that require understanding of these rules. In future versions of WebWork, will be trying to make the tag syntax even simpler |
Some Examples
The most basic example explaining how the tag syntax works is as follows. This example shows off rule #1 only:
...
<ww:textfield label="%{getText("state.label")}" name="state"/>
tags are designed to display dynamic data. To create a input field that displays the property "postalCode", we'd pass the String "postalCode" to the textfield tag.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<s:textfield name="postalCode"/>
|
If there is a "postalCode" property on the value stack, its value will be set to the input field. When the field is submitted back to the framework, the value of the control will be set back to the "postalCode" property.
Sometimes, we want to pass the dynamic data to a tag. For example, we might want to display a label with the input field, and we might want to obtain the label from the application's messages resources. Accordingly, the framework will parse expressions found in the tag attributes, so that we can merge dynamic data into the tag attributes at runtime. The expression escape sequence is "%{ ... }". Any text embedded in the escape sequence is evalulated as an expression.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<s:textfield key="postalCode.label" name="postalCode"/>
|
The expression language (OGNL) lets us call methods and evaluate properties. The method getText
is provided by ActionSupport, which is the base class for most Actions. Since the Action is on the stack, we can call any of its methods from an expression, including getText
.
Non-String Attributes
The HTTP protocol is text-based, but some tags have non-String attribute types, like bool
or int
. To make using non-String attributes intuitative, the framework evaulates all non-String attributes as an expression. In this case, you do not need to use the escape notation. (But, if you do anyway , the framework will just strip it off.)
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<s:select key="state.label |
In this example, the label is dynamically evaluated and set to the outcome of the OGNL expression getText("state.label"), which will in turn invoke the Internationalization system are retrieve the value of the i18n key state.label. The name, being a String attribute, is simply set to the string state.
The next example shows off rule #2:
Code Block | ||
---|---|---|
xml | xml |
<ww:select label="%{getText("state.label")}" name="state" multiple="true"/>
|
While this looks very similar to the last example, the key thing to recognize is that the multiple attribute is of type Boolean, which means it falls under rule #2. Generally you won't even notice this, because true as an OGNL expression evaluated to true, which is what you want.
Since the attribute multiple
maps to a boolean property, the framework does not interpret the value as a String. The value is evaluated as an expression and automtically converted to a boolean.
Since it's easy to forget which attributes are String and which are non-String, you can still use the escape notation.Now let's suppose we want to extend this example to show off rule #3 by making the multiple attribute dynamic:
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<s <ww:select key="state.label" name="%{state" multiple="%{true}"/> |
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<s:select key=getText("state.label" name="state" multiple="allowMultiple"/> |
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<s:select key="state.label)}" name="state" multiple="%{allowMultiple}"/> |
Because the attribute is of type Boolean and starts and ends with the correct characters from rule #3, it is reduced to the expression allowMultiple, which is evaluated against the value stack, returning a true of false value, just like in the previous example.
value
is an Object!
Most often, the value
attribute is set automatically, since name
attribute usually tells the framework which property to call to set the value
. But, if there is a reason to set the value
directly, be advised that value
is an Object NOT a String.
Since
value
is not a String, whatever is passed to value
is evaluated as an expression - NOT a String literal.There is one trick example to keep an eye on, however. For example, the following is probably incorrect:
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<s <ww:textfield labelkey="%{getText("state.label")}" name="state" value="CAca"/> |
This example will only work if the expression CA can result in something, meaning that your action has a method getCA(), which is probably not what you expected. This is because the value attribute is of type Object and therefore rule #2 applies. If the desire is to set a static String as the initial value, you would need to supply an OGNL expression that returns a String. For example, this is the correct way to do it:If a textfield
is passed the value attribute "ca"
, the framework will look for a property named getCa
. Generally, this is not what we mean. What we mean to do is pass a literal String. In the expression language, literals are placed within quotes
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<ww<s:textfield labelkey="%{getText("state.label")}" name="state" value="%{'CAca'}" /> |
...
Another approach would be to use the idiom value="'ca'"
, but, in this case, using the expression notation is recommended.
Boiled down, the tag attributes are evaluated using three rules.
- All String attribute types are parsed for the "%{ ... }" notation.
- All non-String attribute types are not parsed, but evaluated directly as an expression
- The exception to rule #2 is that if the non-String attribute uses the escape notion "%{}", the notation is ignored as redundant, and the content evaluated.
Note |
---|
Please remember about altSyntax option that can change when value is evaluated as an expression - Alt Syntax |
Expression Language Notations
| A JavaBean object in a standard context in Freemarker, Velocity, or JSTL EL (Not OGNL). | ||
| A username property on the Value Stack. | ||
| Another way to refer to a property placed on the Value Stack. | ||
| The username property of the User object in the Session context. | ||
| A static Map, as in put("username","trillian"). |
Disallowed property names
The following names of property are disallowed:
- parameters
- application
- session
- struts
- request
- servletRequest
- servletResponse
The below code will not work:
Code Block | ||||
---|---|---|---|---|
| ||||
<s:iterator value="parameters"/>
|
Code Block | ||||
---|---|---|---|---|
| ||||
public class MyAction {
private String[] parameters;
public String[] getParameters() {
return parameters;
}
}
|