Results 1 to 8 of 8

Thread: JSTL nested foreach problem

  1. #1
    Join Date
    Dec 2010
    Location
    Canberra
    Posts
    6

    Default JSTL nested foreach problem

    Hi All,

    I'm having an issue with a nested JSTL foreach loop. The inner loop isn't recognising the inner list attribute. The outer loop works fine. When the foreach statement on the inner loop is reached the code throws an exception. From looking at other threads with similar exceptions this usually indicates that a form backing object doesn't have a property getter/setter matching the referenced attribute. I believe I do have the appropriate objects. When I output the value of ${myApp} it is a CheckBoxForm object. When I output the value of ${myApp.subRoleList} it outputs a list of Checkbox objects. Any help would be appreciated.

    Regards Andy

    Code:
    [#|2011-04-04T12:50:31.130+1000|WARNING|glassfish3.0.1|javax.enterprise.system.container.web.com.sun.enterprise.web|_ThreadID=27;_ThreadName=http-thread-pool-8080-(2);|StandardWrapperValve[userDetails]: PWC1406: Servlet.service() for servlet userDetails threw exception
    org.springframework.beans.NotReadablePropertyException: Invalid property 'subRolesList[0]' of bean class [au.gov.customs.ldap.domain.CheckBoxFormList]: Bean property 'subRolesList[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.getPropertyValue(BeanWrapperImpl.java:707)
    	at org.springframework.beans.BeanWrapperImpl.getNestedBeanWrapper(BeanWrapperImpl.java:555)
    	at org.springframework.beans.BeanWrapperImpl.getBeanWrapperForPropertyPath(BeanWrapperImpl.java:532)

    CheckBoxFormList.java
    This is the outer list of CheckBoxForm elements

    Code:
    import java.util.ArrayList;
    import java.util.List;
    
    public class CheckBoxFormList {
    
    	private List<CheckBoxForm> applications = new ArrayList<CheckBoxForm>();
    
    	public List<CheckBoxForm> getApplications() {
    		return applications;
    	}
    
    	public void setApplications(List<CheckBoxForm> applications) {
    		this.applications = applications;
    	}
    
    }
    CheckBoxForm.java

    Code:
    import java.util.ArrayList;
    import java.util.List;
    
    public class CheckBoxForm {
    
    	private List<CheckBox> subRolesList = new ArrayList<CheckBox>();
    	private CheckBox app;
    
    	public CheckBox getApp() {
    		return app;
    	}
    
    	public void setApp(CheckBox app) {
    		this.app = app;
    	}
    
    	
    	public List<CheckBox> getSubRolesList() {
    		return subRolesList;
    	}
    
    	
    	public void setSubRolesList(List<CheckBox> subRolesList) {
    		this.subRolesList = subRolesList;
    	}
    
    }
    CheckBox.java
    Code:
    public class CheckBox {
    
    	
    	private String itemLabel;
    	private boolean itemValue;
    	private String roleName;
    	private boolean subRole;
    
    	public boolean isSubRole() {
    		return subRole;
    	}
    
    	public void setSubRole(boolean isSubRole) {
    		this.subRole = isSubRole;
    	}
    
    	public String getRoleName() {
    		return roleName;
    	}
    
    	public void setRoleName(String roleName) {
    		this.roleName = roleName;
    	}
    
    	public String getItemLabel() {
    		return itemLabel;
    	}
    
    	public void setItemLabel(String description) {
    		this.itemLabel = description;
    	}
    	
    	public boolean getItemValue() {
    		return itemValue;
    	}
    	
    	public void setItemValue(boolean selected) {
    		this.itemValue = selected;
    	}
    
    }
    Code:
    				<form:form name="updateRolesForm"  modelAttribute="checkBoxFormList" action="updateUserRoles.htm" method="post">
    					<table class="detail">
    						<tbody>
    							<c:forEach  var="myApp" items="${checkBoxFormList.applications}" varStatus="outer">
    								<ul class="roles">
    								<c:if test="${outer.index mod 2 == 0 }"><tr></c:if>
    								<td>
    								
    								<li class="role">
    								<form:checkbox path="applications[${outer.index}].app.itemValue" /><c:out value="${myApp.app.itemLabel}" /></li>
    								<form:hidden path="applications[${outer.index}].app.subRole"/>
    								<form:hidden path="applications[${outer.index}].app.roleName"/>
    								<form:hidden path="applications[${outer.index}].app.itemLabel"/>
    								<c:out value="${myApp}"></c:out>
    					<!--fails here-->			<c:forEach var="rolesList"  items="${myApp.subRolesList}" varStatus="inner">
    								<ul class="roles">
    									<li class="role"><form:checkbox path="subRolesList[${inner.index}].itemValue" /><c:out value="${rolesList[inner.index].itemLabel}" /></li>
    									<form:hidden path="subRolesList[${inner.index}].subRole"/> 
    									<form:hidden path="subRolesList[${inner.index}].roleName"/> 
    									<form:hidden path="subRolesList[${inner.index}].itemLabel"/> 
    								</ul>
    									
    								</c:forEach>
    								
    								</td>
    								<c:if test="${outer.index mod 2 == 0 }"></tr></c:if>
    								</ul>
    							</c:forEach>
    							
    						</tbody>
    					</table>
    					<input type="submit" value="Update Roles" class="submitBtn" />
    </form:form>

  2. #2
    Join Date
    Jun 2006
    Location
    The Netherlands
    Posts
    13,632

    Default

    Have you actually read the stacktrace....

    There is no getSubRolesList method on your formbacking/modelobject... Your path is wrong. it should include the applications also.

    Code:
    path="applications[outer.index].subRolesList[inner.index]
    Marten Deinum
    Java Consultant / Pragmatist / Open Source Enthousiast / Author


    Pro Spring MVC: With Web Flow
    Conspect

    Have you read the reference guide.
    Use the [ code ] tags, young padawan

  3. #3
    Join Date
    Dec 2010
    Location
    Canberra
    Posts
    6

    Default Thanks

    Thanks Martin.

    I (wrongly) assumed that relative paths could be used in the nested loop. noob Once the full paths to the backing object are used it works.

    Thanks again.

  4. #4
    Join Date
    Aug 2006
    Location
    Arequipa-Peru / South America
    Posts
    2,796

    Default

    Hello staringclown

    Just curious, could you please post an image about what generate your form?
    I want see clearly what generate your two forEach

    Thanks in advanced
    - Manuel Jordan

    Kill Your Pride, Share Your Knowledge With All
    The Fear Of The LORD Is The Beginning Of Knowledge, But Fools Despise Wisdom And Discipline. Proverbs 1:7

    Blog


    Technical Reviewer of Apress

    • Pro SpringSource dm Server
    • Spring Enterprise Recipes: A Problem-Solution Approach
    • Spring Recipes: A Problem-Solution Approach, 2nd Edition
    • Pro Spring Integration
    • Pro Spring Batch
    • Pro Spring 3
    • Pro Spring MVC: With Web Flow
    • Pro Spring Security

  5. #5
    Join Date
    Dec 2010
    Location
    Canberra
    Posts
    6

    Default

    Apologies for the tardiness of the reply. It was a public holiday in Oz.

    Not sure exactly what you mean by what generates my form but here's my working code.

    I have a checkbox class. I have a checkbox per application and a sublist of checkboxes of the roles for that application (checkboxform). Finally I have a list of applications and an associated user and their organisation. (checkboxformlist)

    The naming could probably be better.

    Code:
    public class CheckBox {
    
    	private String itemLabel;
    	private boolean selected;
    	private String roleName;
    	private boolean subRole;
    
    	public boolean isSelected() {
    		return selected;
    	}
    
    	public void setSelected(boolean selected) {
    		this.selected = selected;
    	}
    
    	public boolean isSubRole() {
    		return subRole;
    	}
    
    	public void setSubRole(boolean isSubRole) {
    		this.subRole = isSubRole;
    	}
    
    	public String getRoleName() {
    		return roleName;
    	}
    
    	public void setRoleName(String roleName) {
    		this.roleName = roleName;
    	}
    
    	public String getItemLabel() {
    		return itemLabel;
    	}
    
    	public void setItemLabel(String description) {
    		this.itemLabel = description;
    	}
    
    }
    Code:
    import java.util.List;
    
    public class CheckBoxForm {
    
    	private List<CheckBox> subRoleList;
    	private CheckBox app;
    
    	public List<CheckBox> getSubRoleList() {
    		return subRoleList;
    	}
    
    	public void setSubRoleList(List<CheckBox> subRoleList) {
    		this.subRoleList = subRoleList;
    	}
    
    	public CheckBox getApp() {
    		return app;
    	}
    
    	public void setApp(CheckBox app) {
    		this.app = app;
    	}
    
    }

    Code:
    public class CheckBoxFormList {
    	private String user;
    	private String organisation;
    	private List<CheckBoxForm> applications;
    
    	public String getOrganisation() {
    		return organisation;
    	}
    
    	public void setOrganisation(String organisation) {
    		this.organisation = organisation;
    	}
    
    	public String getUser() {
    		return user;
    	}
    
    	public void setUser(String customsUser) {
    		this.user = customsUser;
    	}
    
    	public List<CheckBoxForm> getApplications() {
    		return applications;
    	}
    
    	public void setApplications(List<CheckBoxForm> applications) {
    		this.applications = applications;
    	}
    
    }
    The controller calls a webservice that updates the roles accordingly

    Code:
    @RequestMapping(value = "/updateUserRoles.htm", method = RequestMethod.POST)
    	public String submitUpdateApplicationRoles(
    			@ModelAttribute("checkBoxFormList") CheckBoxFormList checkBoxFormList,
    			BindingResult result) throws IDMException {
    
    		String uid = checkBoxFormList.getUser();
    		String org = checkBoxFormList.getOrganisation();
    
    		if (org == null || uid == null) {
    			String message = "Organisation or Customs User cannot be null";
    			logger.error(message);
    			throw new IDMException(message);
    		}
    		CustomsUser loggedInUser = (CustomsUser) SecurityContextHolder
    				.getContext().getAuthentication().getPrincipal();
    		if (!hasAccess(org, uid, loggedInUser)) {
    			String message = "You don't have the authorisation to perform this action";
    			logger.error(message);
    			throw new IDMException(message);
    		}
    		UpdateTamRolesRequest updateTamRolesRequest = new UpdateTamRolesRequest();
    		updateTamRolesRequest.setApplicationRoles(new CheckBoxFormListJAXB(
    				checkBoxFormList));
    		updateTamRolesRequest.setOrganisation(org);
    		updateTamRolesRequest.setCustomsUser(uid);
    		proxy.callIDMWebService(IDMWebServiceCallType.EXTERNAL,
    				updateTamRolesRequest);
    
    		return "redirect:displayUser.htm?organisation=" + org + "&uid=" + uid;
    	}

    The JSTL/JSP stuff


    Code:
    <form:form name="updateRolesForm"  modelAttribute="checkBoxFormList" action="updateUserRoles.htm" method="post">
    	<table class="detail">
    		<tbody>
    		
    		<form:hidden path="user" value="${customsUser.uid}"/>
    		<form:hidden path="organisation" value="${organisation.businessNumber}"/>
    		<c:if test="${status.error}">
    			<tr class="errors">
    				<td>
    					<form:errors/>
    				</td>
    			</tr>
    		</c:if>
    			<c:forEach  var="myApp" items="${checkBoxFormList.applications}" varStatus="outer">
    				<ul class="roles">
    				<c:if test="${outer.index mod 2 == 0 }">
    					<tr valign="top">
    				</c:if>
    				<td>
    					<li class="role"><form:checkbox path="applications[${outer.index}].app.selected" /><c:out value="${myApp.app.itemLabel}" /></li>
    					<form:hidden path="applications[${outer.index}].app.subRole"/>
    					<form:hidden path="applications[${outer.index}].app.roleName"/>
    					<form:hidden path="applications[${outer.index}].app.itemLabel"/>
    						<c:forEach var="roleList"  items="${checkBoxFormList.applications[outer.index].subRoleList}" varStatus="inner">
    						<ul class="roles">
    							<li class="role"><form:checkbox path="applications[${outer.index}].subRoleList[${inner.index}].selected" /><c:out value="${roleList.itemLabel}" /></li>
    							<form:hidden path="applications[${outer.index}].subRoleList[${inner.index}].subRole"/> 
    							<form:hidden path="applications[${outer.index}].subRoleList[${inner.index}].roleName"/> 
    							<form:hidden path="applications[${outer.index}].subRoleList[${inner.index}].itemLabel"/> 
    						</ul>
    									
    						</c:forEach>
    				</td>
    					<c:if test="${outer.index mod 2 == 0 && outer.index != 0}">
    						</tr>
    					</c:if>
    				</ul>
    			</c:forEach>							
    		</tbody>
    	</table>
    		<input type="submit" value="Update User Permissions" class="submitBtn" />
    </form:form>
    Hope this helps. Let me know if you need any more info.

    Cheers
    Andy

    Edit wrong jsp

  6. #6
    Join Date
    Aug 2006
    Location
    Arequipa-Peru / South America
    Posts
    2,796

    Default

    Hello Andy

    Thanks for the reply and for post the code

    Not sure exactly what you mean by what generates my form but here's my working code.
    I apologize for my bad English

    I have a checkbox class. I have a checkbox per application and a sublist of checkboxes of the roles for that application (checkboxform). Finally I have a list of applications and an associated user and their organisation. (checkboxformlist)
    Ok, thanks for the explanation, but to get the complete idea, Could you post an image about what generate your code, I mean the view for the client?

    Thank you
    - Manuel Jordan

    Kill Your Pride, Share Your Knowledge With All
    The Fear Of The LORD Is The Beginning Of Knowledge, But Fools Despise Wisdom And Discipline. Proverbs 1:7

    Blog


    Technical Reviewer of Apress

    • Pro SpringSource dm Server
    • Spring Enterprise Recipes: A Problem-Solution Approach
    • Spring Recipes: A Problem-Solution Approach, 2nd Edition
    • Pro Spring Integration
    • Pro Spring Batch
    • Pro Spring 3
    • Pro Spring MVC: With Web Flow
    • Pro Spring Security

  7. #7
    Join Date
    Dec 2010
    Location
    Canberra
    Posts
    6

    Default

    Attached is a jpg of the clients view

    checkboxes.jpg

  8. #8
    Join Date
    Aug 2006
    Location
    Arequipa-Peru / South America
    Posts
    2,796

    Default

    OK, now I have the complete idea

    Thank you!
    - Manuel Jordan

    Kill Your Pride, Share Your Knowledge With All
    The Fear Of The LORD Is The Beginning Of Knowledge, But Fools Despise Wisdom And Discipline. Proverbs 1:7

    Blog


    Technical Reviewer of Apress

    • Pro SpringSource dm Server
    • Spring Enterprise Recipes: A Problem-Solution Approach
    • Spring Recipes: A Problem-Solution Approach, 2nd Edition
    • Pro Spring Integration
    • Pro Spring Batch
    • Pro Spring 3
    • Pro Spring MVC: With Web Flow
    • Pro Spring Security

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •