One of the most frustrating things I run into when developing Struts applications is the problem of when you want to use a request scoped ActionForm but you need to populate a collection that is one of your ActionForm properties. The problem is the classic index out of bounds exception if you do not have your collection populated with enough objects.

For example imagine the case where you might want to edit a bunch of Access definitions on one form.

So in an ActionForm property you have:

Collection accessDefinitions;

In your Action before you get to the form you populate your form:

((AccessForm)form).setAccessDefinitions( aCollectionOfDefs );

Your JSP then displays the access definition properties for the user to edit:

(condensed and table formatting removed:)

<c:forEach items="${accessForm.accessDefinitions}" var="access" varStatus="status">
<html:text property="accessDefinitions[${status.index}].name"/>
<html:text property="accessDefinitions[${status.index}].description"/>
</c:forEach>


Now the problem will be when you submit this form. If this form was given request scope in the action mapping, you'll end up with errors since BeanUtils can not populate the Collection. You need to have the correct size in place for 'accessDefinitions' to allow for population.

There are several solutions that have been proposed by searching the list archives.

The easiest alternative is of course to just put your form in Session scope, but that is such a waste in my opinion.

Another approach would be something like:

In reset() of ActionForm:

public void reset(ActionMapping actionMapping, HttpServletRequest request) {
if ( request.getParameter("accessDefinitionsSize") != null ) {
int accessDefinitionsSize = new Integer(request.getParameter("accessDefinitionsSize")).intValue();
accessDefinitions = new ArrayList(accessDefinitionsSize);
for (int i=0;i<accessDefinitionsSize;i++) {
accessDefinitions.add(new AccessDefinitionVO());
}
}
}


Then in your JSP (code snipped just showing releveant portion):

<c:forEach items="${accessForm.accessDefinitions}" var="access" varStatus="status">
....
<c:set var="accessDefinitionsSize" value="${status.count}"/>
</c:forEach>
<input type="hidden" name="accessDefinitionsSize" value="${accessDefinitionsSize}"/>


The above works 'ok' but it's so much extra code. I've thought of just adding the accessDefinitionsSize attribute to the Session in the Action that is called right be the form is set up. Then the reset method can pull it right from there. An int in the session won't be too much overhead. But I'm not sure if I like that approach that much either (although I'm leaning towards just doing it that way).

Of course I don't like the approaches that call a business class from the reset to get the size.

Any suggestions welcome.

--
Rick



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



Reply via email to