Thursday, October 11, 2012

Struts 2: Populate data for page even after validation failed

I recently added a validation interceptor in one of our Struts 2 applications, but got some errors when validation failed. It took me some time to figure out the error since all exceptions have been redirected to a global exception page, and no logging was written.

Anyway, the error is:
The requested list key 'sortTypeList' could not be resolved as a collection/array/map/enumeration/iterator type.
After some investigation, I figured out the reason being that there is a piece of code in the action method to prepare this list to be dispalyed on the jsp page as a drop down list:

    sortTypeList=new ArrayList();
    sortTypeList.add(new KeyValueVO("id", getText("label.id")));
    sortTypeList.add(new KeyValueVO("name", getText("label.name")));

When the validation fails, this piece of code won't run, leaving the list not being populated. Where KeyValueVO is a class contains two Strings: key and value.

To avoid this, Struts 2 provided an interface Preparable, which has one method:
    public void prepare();

I made the action implement Preparable interface and moved the above code to inside prepare method. It worked properly.

My action also contains a few other method for different actions, not all of them will need populate this list. I made the method prepare empty, and move the code to new methods named as prepare(). For example, the list is needed in sort(), and search(), but not delete(). I created new methods for them:

    prepareSort() { // will run before sort() ...
    prepareSearch() { // will run before search() ... 
The prepare methods are invoked by the interceptor below:
    <interceptor-ref name="prepare"/>
So, you'll need to make sure it is on the interceptor stack and it appears before interceptor "validation".
    <interceptor-ref name="prepare"/>
    ... 
    <interceptor-ref name="validation"/> 
The preparable interceptor supports a parameter: alwaysInvokePrepare. By default it's true, meaning the prepare methods will run.

There are more details can be found in http://struts.apache.org/2.2.1/docs/prepare-interceptor.html, and this link shows an additional solution: http://struts.apache.org/2.2.1/docs/how-do-we-repopulate-controls-when-validation-fails.html.

No comments: