Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

WebWork has one of the most advanced type conversion abilities in any web-based framework in any Java language. Generally, you don't need to do anything to take advantage of it, other than name your HTML inputs (form elements and other GET/POST parameters) names that are valid OGNL expressions.

A Simple Example

Wiki Markup
{snippet:id=javadoc|javadoc=true|url=com.opensymphony.xwork.util.XWorkConverter}
Note
Wiki Markup
{snippet:id=i18n-note|javadoc=true|url=com.opensymphony.xwork.util.XWorkConverter}

WebWork ships with a helper base class that makes converting to and from Strings very easy. The class is com.opensymphony.webwork.util.WebWorkTypeConverter. This class makes it very easy for you to write type converters that handle converting objects to Strings as well as from Strings. From the JavaDocs for this class:

Wiki Markup
{snippet:id=javadoc|javadoc=true|url=com.opensymphony.webwork.util.WebWorkTypeConverter}

Built in Type Conversion Support

Wiki Markup
{snippet:id=javadoc|javadoc=true|url=com.opensymphony.xwork.util.XWorkBasicConverter}

Relationship to Parameter Names

The best way to take advantage of WebWork's type conversion is to utilize complete objects (ideally your domain objects directly), rather than submitting form values on to intermediate primitives and strings in your action and then converting those values to full objects in the execute() method. Some tips for achieving this are:

  • Use complex OGNL expressions - WebWork will automatically take care of creating the actual objects for you.
  • Use JavaBeans! WebWork can only create objects for you if your objects obey the JavaBean specification and provide no-arg constructions, as well as getters and setters where appropriate.
  • Remember that person.name will call getPerson().setName(), but if you are expecting WebWork to create the Person object for you, a setPerson() must also exist.
  • Wiki Markup
    For lists and maps, use index notation, such as _people\[0\].name_ or _friends\['patrick'\].name_. Often these HTML form elements are being rendered inside a loop, so you can use the iterator tag's status attribute if you're using [JSP Tags] or the $\{foo_index\} special property if you're using [FreeMarker Tags].
  • FOr multiple select boxes, you obviously can't name each individual item using index notation. Instead, name your element simply people.name and WebWork will understand that it should create a new Person object for each selected item and set it's name accordingly.

Advanced Type Conversion

WebWork also has some very advanced, yet easy-to-use, type conversion features. Null property handling will automatically create objects where null references are found. Collection and map support provides intelligent null handling and type conversion for Java Collections. Type conversion error handling provides an easy way to distinguish the difference between an input validation problem from an input type conversion problem.

Null Property Handling

Wiki Markup
{snippet:id=javadoc|javadoc=true|url=com.opensymphony.xwork.util.InstantiatingNullHandler}
Wiki Markup
{snippet:id=example|javadoc=true|url=com.opensymphony.xwork.util.InstantiatingNullHandler}

Collection and Map Support

WebWork supports ways to determine the object type found in collections. This is done via an ObjectTypeDeterminer. The default implementation is provided. The JavaDocs explain how map and colelction support is determined in the DefaultObjectTypeDeterminer:

Wiki Markup
{snippet:id=javadoc|javadoc=true|url=com.opensymphony.xwork.util.DefaultObjectTypeDeterminer}

Additionally, you can create your own custom ObjectTypeDeterminer by implementing the ObjectTypeDeterminer interface. There is also an optional ObjectTypeDeterminer that utilizes Java 5 generics. See the J2SE 5 Support page for more information.

Indexing a collection by a property of that collection

It is also possible using webwork to get a unique element of a collection, by passing the value of a given property of that element. By default, the property of the element of the collection is determined in Class-conversion.properties using KeyProperty_xxx=yyy where xxx is the property of the bean 'Class' that returns the collection and yyy is the property of the collection element that we want to index on. Here is an example with the following two classes:

Code Block
titleMyAction.java
borderStylesolid

/**
 * @return a Collection of Foo objects
 */
public Collection getFooCollection()
{
    return foo;
}
Code Block
titleFoo.java
borderStylesolid

/**
 * @return a unique identifier
 */
public Long getId()
{
    return id;
}

Then put KeyProperty_fooCollection=id in my MyAction-conversion.properties file. This would allow to the use of fooCollection(someIdValue) to get the Foo object with value someIdValue in the Set fooCollection. For example, fooCollection(22) would return the Foo object in the fooCollection collection whose id property value was 22.

This is useful, because it ties a collection element directly to its unique identifier and therefore does not force you to use an index and thus allows you to edit the elements of a collection associated to a bean without any additional code. For example, parameter name fooCollection(22).name and value Phil would set name the Foo object in the fooCollection collection whose id property value was 22 to be Phil.

Webwork automatically converts the type of the parameter sent in to the type of the key property using type conversion.

Wiki Markup
Unlike Map and List element properties, if fooCollection(22) does not exist it will not be created. To do that, use the notation *fooCollection.makeNew\[index\]* where index is an integer 0, 1, and so on. Thus, parameter value pairs *fooCollection.makeNew\[0\]=Phil* and *fooCollection.makeNew\[1\]=John* would add two new Foo objects to fooCollection one with name property value Phil and the other with name property value Bar. Note, however, that in the case of a Set, the equals and hashCode methods should be defined such that they don't only include the id property. That will cause one element of the null id propertied Foos to be removed from the Set.

An advanced example for indexed Lists and Maps

Here is the model bean used within the list.
The KeyProperty for this bean is the id attribute.

Code Block
titleMyBean.java
borderStylesolid
public class MyBean implements Serializable {

    private Long id;
    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }


    public String toString() {
        return "MyBean{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

The action has a beanList attribute initialized with an empty ArrayList.

Code Block
titleMyBeanAction.java
borderStylesolid
ublic class MyBeanAction implements Action {

    private List beanList = new ArrayList();
    private Map beanMap = new HashMap();

    public List getBeanList() {
        return beanList;
    }

    public void setBeanList(List beanList) {
        this.beanList = beanList;
    }

    public Map getBeanMap() {
        return beanMap;
    }

    public void setBeanMap(Map beanMap) {
        this.beanMap = beanMap;
    }

    public String execute() throws Exception {
        return SUCCESS;
    }
}

These conversion.properties tell the TypeConverter to use MyBean instances as elements of the List.

Code Block
titleMyBeanAction-conversion.properties
borderStylesolid
KeyProperty_beanList=id
Element_beanList=MyBean
CreateIfNull_beanList=true

When submitting this via a form, the (id) value is used as KeyProperty for the MyBean instances in the beanList.
Notice the () notation! Do not use [] notation, this is for Maps only!
The value for name will be set to the MyBean instance with this special id.
The List does no longer have null values added for unavailable id values.
This avoids the risk of OutOfMemoryErrors!

Code Block
titleMyBeanAction.jsp
borderStylesolid
<ww:iterator value="beanList" id="bean">
  <ww:textfield name="beanList(%{bean.id}).name" />
</ww:iterator>

Type Conversion Error Handling

Wiki Markup
{snippet:id=error-reporting|javadoc=true|url=com.opensymphony.xwork.util.XWorkConverter}

There are two ways the error reporting can occur:

  1. globally, using the Conversion Error Interceptor
  2. on a per-field basis, using the conversion validator

By default, the conversion interceptor is included in webwork-default.xml in the default stack, so if you don't want conversion errors reporting globally, you'll need to change the interceptor stack and add additional validation rules.