You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 24 Next »

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

Error formatting macro: snippet: java.lang.NullPointerException
Error formatting macro: snippet: java.lang.NullPointerException

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:

Error formatting macro: snippet: java.lang.NullPointerException

Built in Type Conversion Support

Error formatting macro: snippet: java.lang.NullPointerException

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.
  • 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

Error formatting macro: snippet: java.lang.NullPointerException
Error formatting macro: snippet: java.lang.NullPointerException

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:

Error formatting macro: snippet: java.lang.NullPointerException

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:

MyAction.java

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

/**
 * @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.

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.

MyBean.java
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.

MyBeanAction.java
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.

MyBeanAction-conversion.properties
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!

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

Type Conversion Error Handling

Error formatting macro: snippet: java.lang.NullPointerException

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.

  • No labels