Thursday, May 1, 2008

Working with collections

If we have to iterate a Collection in struts and were required to pass back the object values from the collection as hidden fields to be set in the form, we would get an ArrayIndexOutofBounds exception. This is because we cannot set the collection as is. We need a special handling to add the objects to the collection from the jsp to form like the example given below.

Create a class called CustomList as follows

public class CustomList extends ArrayList {

private Class elementType;
private int maximumGrowSize;

public CustomList(Class elementType, int maximumGrowSize) {
this.elementType = elementType;
this.maximumGrowSize = maximumGrowSize;
}

public Object get(int index) {
while(index >= size()) {
if (index > maximumGrowSize) {
throw new RuntimeException("Cannot allow list to automatically grow beyond " + maximumGrowSize);
}
try {
add(elementType.newInstance());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return super.get(index);
}
}

In struts Action Form, we add

private List records = new CustomList(Person.class, 1000);
where Person.java is our model object which is populated in the collection

Sometimes we may have to display checkboxes next to each record to give the user option to delete selected records.
In such a case we handle the code as below:

<logic:iterate property="records">
<tr class="<%=rowClass%>" style="text-align:center">
<td>
<logic:checkbox property="delete" />
</td>
<td>
<logic:hidden property="personName"/>
<logic:write property="personName"/>
</td>
<td>
<logic:hidden property="personAge"/>
<logic:write property="personAge"/>
</td>
</tr>
</logic:iterate>


In the form, we can add a wrapper class to our Person object as shown below

public class PersonForm extends ActionForm
{

private List records = new CustomList(PersonWrapper.class, 1000);

public List getRecords()
{
return records;
}

public void setRecords(List records)
{
this.records = records;
}


public static class PersonWrapper extends Person
{

private boolean delete;

public boolean isDelete()
{
return delete;
}

public void setDelete(boolean delete)
{
this.delete = delete;
}
}

//....

}

Then in our struts Action class, we can get

public class PersonAction extends Action
{

List myRecords = actionForm.getRecords(); //This would have the the delete checkbox value as well in each row of the collection

for (PersonForm.PersonWrapper record : myRecords)
{
if (record.isDelete())
{
// do delete from database....

}
}

//...


//How to populate this result collection for display is as shown below

List<Person> results = databaseHelper.getAllPersonRecords();

if (results.size() > 0)
{
for (int i = 0, n = results.size(); i < n; i++)
{
PersonForm.PersonWrapper rec = new PersonForm.PersonWrapper();
try
{
PropertyUtils.copyProperties(rec, results.get(i));
}
catch (Exception e)
{
logger.error("Error copying Person beans!", e);
}
results.set(i, rec);
}
}

No comments: