Date: 2004-09-30T15:57:57
   Editor: NiallPemberton <[EMAIL PROTECTED]>
   Wiki: Apache Struts Wiki
   Page: StrutsCatalogLazyList
   URL: http://wiki.apache.org/struts/StrutsCatalogLazyList

   no comment

New Page:

There are two frequent issues the confront people when dealing with populating a 
collection of beans in an ActionForm.

 * How can I generate the appropriate html using the struts taglibs?
 * I have a request scoped ActionForm and am getting an "index out of range" error 
when I submit the form - what do I do?


The ''Indexed Properies'' section below deals with generating the html and the ''Lazy 
List'' section shows possible solutions for avoiding the "index out of range" error.

== Indexed Properties ==

Struts html tags have an ''indexed'' attribute which will generate the appropriate 
html to populate a collection of beans when the form is submitted.

For example the following jsp...

{{{
   <html:iterate name="skillsForm" property="skills" id="skills">
       
       <html:text name="skills" property="skillId" indexed="true"/>

   </html:iterate>
}}}

...will generate the following html

{{{
    <input type="text" name="skills[0].skillId value="..."/>
    <input type="text" name="skills[1].skillId value="..."/>
    ....
    <input type="text" name="skills[n].skillId value="..."/>
}}}

When the form is submitted BeanUtils will first call the getSkills(index) method to 
retrieve the indexed bean followed by setSkillId(..) on the retrieved bean.

== Lazy List Behaviour ==

A common problem with indexed properties, is that people then get "index out of range" 
errors with ActionForms that are in Request scope. The indexed property (List or 
Array) needs to be able to automatically ''grow'' during the ActionForm population 
process. The key to achieving this is in the getXXXX(index) method.

The following sections show three examples of how to achieve lazy list processing.


=== Hand Cranking lazy List in the ActionForm ===

{{{

  public class SkillActionForm extends ActionForm {

      protected List skills = new ArrayList();

      public List getSkills() {
          return skills;
      }

      public void setSkills(List skills) {
          this.skills = skills;
      }

      public SkillBean getSkills(int index) {

          // automatically grow List size
          while (index >= skills.size()) {
              skills.add(new SkillBean());
          }

          return skills.get(index);

      }

  }

}}}

=== Using Commons Collections for lazy Lists ===

Commons collections have a lazy list decorator which automatically grows the list when 
the get(int) method is called. In the example below the ActionForm implements the 
Factory interface, providing the create() method to populate an entry in the List.


{{{

  import org.apache.commons.collections.Factory;
  import org.apache.commons.collections.list.LazyList;

  public class SkillActionForm extends ActionForm, implements Factory {

      protected List skills = LazyList.decorate(new ArrayList(), this);

      public List getSkills() {
          return skills;
      }

      public void setSkills(List skills) {
          this.skills = skills;
      }

      public SkillBean getSkills(int index) {
          return skills.get(index);
      }

      // 'Factory' method for LazyList
      public Object create() {
          return new SkillBean();
      }

  }

}}}

=== LazyDynaBean / LazyValidatorForm ===

'''N.B.''' Solutions here require '''Struts 1.2.4''' and '''Bean Utils 1.7.0'''

[http://jakarta.apache.org/commons/beanutils/commons-beanutils-1.7.0/docs/api/org/apache/commons/beanutils/package-summary.html#dynamic.lazy
 LazyDynaBean] in [http://jakarta.apache.org/commons/beanutils/ Commons BeanUtils] has 
the ''lazy'' List type processing. 
[http://www.niallp.pwp.blueyonder.co.uk/#lazydynabean LazyValidatorForm] is built 
using the BeanUtils LazyDynaBean and can be used by simply configuring it through the 
struts-config.xml.


{{{

  <form-beans>

     <form-bean name="skillForm" type="org.apache.struts.validator.LazyValidatorForm>
        <form-property name="skills" type="java.util.ArrayList"/>
     </form-bean>

  </form-beans> 

}}}

In fact using Arrays (rather than Lists) a LazyDynaBean can be used directly, in the 
following way:

{{{

  <form-beans>

     <form-bean name="skillForm" type="org.apache.commons.beanutils.LazyDynaBean">
        <form-property name="skills" type="myPackage.SkillBean[]"/>
     </form-bean>

  </form-beans> 

}}}

Struts 1.2.4 will ''wrap'' the LazyDynaBean in a BeanValidatorForm automatically.

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to