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 path="grid.blocks[${gridRow.index}].description">
       <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}" />" />
     
     



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…

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s