Tuesday, August 11, 2009

Bind collections to Spring form

 



The Spring Web Tutorial does a good job at explaining how to bind form to the view for display and input purposes. Unfortunately, it is not so easy when we get into forms that have collections.

Form:-
public class Grid {
     private List blocks = new ArrayList();
     public List getBlocks() {
          return blocks;
     }
     public void setBlocks(List list) {
          blocks = list;
     }
}
public class Block {
     private String id, description;
     public String getDescription() {
          return description;
     }
     public String getId() {
          return id;
     }
     public void setDescription(String string) {
          description = string;
     }
     public void setId(String string) {
          id = string;
     }
}


JSP:-

<c:foreach items="${grid.blocks}" varstatus="gridRow">
     <spring:bind path="grid.blocks[${gridRow.index}].id">
      <c:out value="${status.value}" />
        <input type="hidden" name="<c:out value="${status.expression}">
         id="<c:out value="${status.expression}" />"
         value="<c:out value="${status.value}" />" />
       </spring:bind>
       
     <spring:bind path="grid.blocks[${gridRow.index}].description">
       <c:out value="${status.value}" />
        <input type="hidden" name="&lt;c:out value="${status.expression}">
         id="<c:out value="${status.expression}" />"
         value="<c:out value="${status.value}" />" />
     </spring:bind>
     
</c:foreach>


But this does not work and throws the following exception:-
  InvalidPropertyException: Invalid property 'blocks[1].id' of bean class [Grid]: Index of out of bounds in property path 'blocks[1]'; nested exception is java.lang.IndexOutOfBoundsException: Index: 1, Size: 0 
This is explained very well in the following articles   
1.
Dynamic list binding in Spring

2. Dynamic list binding problem...why? object graph


The workaround is to decorate the ArrayList with LazyList
Form:-

public class Grid { 
      private List blocks = LazyList.decorate( new ArrayList(), 
            FactoryUtils.instantiateFactory(Block.class)); 
 
      public List getBlocks() { 
            return blocks; 
      } 
 
      public void setBlocks(List list) { 
            blocks = list; 
      } 
} 

The rest of the code does not change and I had the desired results :-) Try it and let me know if it works...

No comments:

Post a Comment

Thank you for your feedback