PDA

View Full Version : Collections (ArrayList), web flow forms, and data binding



John.Turner
Dec 11th, 2007, 01:42 AM
G'day All,

I have a requirement to retrieve a list of objects from the database, display them in a 'multi-record' form so that they can be edited, and then save the modified records back to the database. I have set up a web flow to retrieve the records from the database, and then present them to the user in a form. I am having problems binding the data to the form. I am also not sure how to access the data after it has been posted.

I have read a large number of threads on this forum and experimented with different syntax in the JSP file but still cannot render a JSP containing a form with the data bound.

I am using Spring v2.5 and Spring Web Flow v1.0.5.

Spring beans config:



<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResou rceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.tiles.TilesJs tlView" />
</bean>

<bean id="urlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlH andlerMapping">
<property name="mappings">
<props>
<prop key="flow.htm">flowController</prop>
</props>
</property>
</bean>

<bean id="tilesConfigurer"
class="org.springframework.web.servlet.view.tiles.TilesCo nfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/foo-tiles.xml</value>
</list>
</property>
</bean>

<bean id="flowController"
class="org.springframework.webflow.executor.mvc.FlowContr oller">
<property name="flowExecutor" ref="flowExecutor" />
</bean>

<flow:executor id="flowExecutor" registry-ref="flowRegistry" />

<flow:registry id="flowRegistry">
<flow:location path="/WEB-INF/flow/**/*-flow.xml" />
</flow:registry>

<bean id="retrieveRelationshipTypesAction"
class="foo.action.RetrieveRelationshipTypesAction">
</bean>

<bean id="saveRelationshipTypeAction"
class="foo.action.SaveRelationshipTypeAction"/>

<bean id="relationshipTypeFormAction"
class="foo.form.RelationshipTypeFormAction">
<property name="formObjectName" value="rtList"/>
<property name="formObjectScope" value="REQUEST" />
<property name="formObjectClass" value="java.util.ArrayList"/>
</bean>


Web flow definition:



<var name="relationshipTypes" class="java.util.ArrayList" scope="flow" />

<start-state idref="retrieveRelationshipTypes" />

<action-state id="retrieveRelationshipTypes">
<action bean="retrieveRelationshipTypesAction" />
<transition on="success" to="showRelationshipTypes" />
</action-state>

<view-state id="showRelationshipTypes" view="relationshipType.page" >
<render-actions>
<action bean="relationshipTypeFormAction" method="setupForm"/>
<action bean="relationshipTypeFormAction" method="populateList"/>
</render-actions>
<transition on="select" to="saveRelationshipType" >
<action bean="relationshipTypeFormAction" method="bind" />
<evaluate-action expression="requestScope.pgOfRelTypes">
<evaluation-result name="flowScope.relationshipTypes" />
</evaluate-action>
</transition>
</view-state>

<action-state id="saveRelationshipType">
<action bean="saveRelationshipTypeAction" />
<transition on="success" to="showRelationshipTypes" />
</action-state>


My action form class is:



package foo.form;

import...

public class RelationshipTypeFormAction extends FormAction {

private static Logger log = Logger.getLogger(RelationshipTypeFormAction.class) ;

public Event populateList(RequestContext context) throws Exception {
log.debug("populateList: in");
ArrayList<ItemRelationshipType> relationshipTypes = (ArrayList<ItemRelationshipType>) context.getFlowScope().get("relationshipTypes");
ArrayList<ItemRelationshipType> rtList = (ArrayList<ItemRelationshipType>) getFormObject(context);
rtList.clear();
rtList.addAll(relationshipTypes);
log.debug("populateList: out");
return success();
}
}


JSP page (I'm using tiles):



<jsp:directive.include file="/WEB-INF/page/tags.jsp" />

<h3>Relationship Types</h3>

<form:form action="flow.htm" commandName="rtList">
<input type="hidden" name="_flowExecutionKey" value="${flowExecutionKey}">
<input type="hidden" name="targetAction" value="error">
<table width="80%">
<tr>
<td>
ID
</td>
<td>
Name
</td>
<td>
Description
</td>
</tr>

<c:forEach items="${rtList}" var="rt" varStatus="loop">
<tr>
<td>
<%-- <c:out value="${rt.itemRelationshipTypeId}" /> --%>
<form:input path="${rtList}[${loop.index}].itemRelationshipTypeId" />
</td>
<td>
<%-- <c:out value="${rt.name}" /> --%>
<form:input path="${rtList}[${loop.index}].name" />
</td>
<td>
<%-- <c:out value="${rt.description}" /> --%>
<form:input path="${rtList}[${loop.index}].description" />
</td>
</tr>
</c:forEach>

</table>
<p>
<input type="submit" name="_eventId_cancel" value="Cancel"/>
<input type="submit" name="_eventId_save" value="Save"/>
</p>
</form:form>


When this JSP is called I get this error:



17:14:11,225 [[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'] ERROR org.springframework.web.servlet.tags.form.InputTag - Invalid property '[foo.model.ItemRelationshipType@79b022, foo.model.ItemRelationshipType@79b00e, foo.model.ItemRelationshipType@79affa][0]' of bean class [java.util.ArrayList]: Bean property '[foo.model.ItemRelationshipType@79b022, foo.model.ItemRelationshipType@79b00e, foo.model.ItemRelationshipType@79affa][0]' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
org.springframework.beans.NotReadablePropertyExcep tion: Invalid property '[foo.model.ItemRelationshipType@79b022, foo.model.ItemRelationshipType@79b00e, foo.model.ItemRelationshipType@79affa][0]' of bean class [java.util.ArrayList]: Bean property '[foo.model.ItemRelationshipType@79b022, foo.model.ItemRelationshipType@79b00e, foo.model.ItemRelationshipType@79affa][0]' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
at org.springframework.beans.BeanWrapperImpl.getPrope rtyValue(BeanWrapperImpl.java:544)
at org.springframework.beans.BeanWrapperImpl.getNeste dBeanWrapper(BeanWrapperImpl.java:451)
at org.springframework.beans.BeanWrapperImpl.getBeanW rapperForPropertyPath(BeanWrapperImpl.java:428)
...


Can anyone tell me what the correct syntax is for binding to a list? I've tried several variations on what I've presented here but with no success.

Thanks, John

Marten Deinum
Dec 11th, 2007, 06:08 AM
You cannot use a List as a formBackingObject. You can use an object containing a List. The samples shipped with Spring provide a working sample of that.

John.Turner
Dec 11th, 2007, 06:04 PM
Marten, Thanks for your suggestion. I now have the binding working OK. Regards, John

For future reference the syntax for binding in the JSP is:



<jsp:directive.include file="/WEB-INF/page/tags.jsp" />

<h3>Relationship Types</h3>

<form:form action="flow.htm" commandName="relationshipTypeForm">
<input type="hidden" name="_flowExecutionKey" value="${flowExecutionKey}">
<input type="hidden" name="targetAction" value="error">
<table width="80%">
<tr>
<td>
ID
</td>
<td>
Name
</td>
<td>
Description
</td>
</tr>

<c:forEach items="${relationshipTypeForm.rtList}" var="rt" varStatus="loop">
<tr>
<td>
<%-- <c:out value="${rt.itemRelationshipTypeId}" /> --%>
<form:input path="rtList[${loop.index}].itemRelationshipTypeId" />
</td>
<td>
<%-- <c:out value="${rt.name}" /> --%>
<form:input path="rtList[${loop.index}].name" />
</td>
<td>
<%-- <c:out value="${rt.description}" /> --%>
<form:input path="rtList[${loop.index}].description" />
</td>
</tr>
</c:forEach>

</table>
<p>
<input type="submit" name="_eventId_cancel" value="Cancel"/>
<input type="submit" name="_eventId_save" value="Save"/>
</p>
</form:form>

geoffreyeaster
May 6th, 2009, 05:25 PM
How are you applying validation to this? How do you refer to the indexed list in your validator?

Shachi Rai
Jun 11th, 2012, 05:44 AM
You cannot use a List as a formBackingObject. You can use an object containing a List. The samples shipped with Spring provide a working sample of that.

Could you please provide the URL for the samples you have referred in your comment