Announcement Announcement Module
Collapse
No announcement yet.
JSTL nested foreach problem Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • 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
    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]

    Comment


    • #3
      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.

      Comment


      • #4
        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

        Comment


        • #5
          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

          Comment


          • #6
            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

            Comment


            • #7
              Attached is a jpg of the clients view

              Attachment
              Attached Files

              Comment


              • #8
                OK, now I have the complete idea

                Thank you!

                Comment

                Working...
                X