tags:

views:

160

answers:

2

Hello,

I have something like this in my Spring Application:

public class Book{ 
    public Book(){
       sheets = new LinkedList<Sheet>();
    }
    protected List<Sheet> sheets;
    //getter and setter 
}

I add several Sheets to the sheet list and I print a form in a JSP like this:

<form:form modelAttribute="book"  action="${dest_url}" method="POST">   
    <c:forEach items="${mybook.sheets}" var="sheet" varStatus="status">
        <form:hidden path="sheet[${status.count -1}].header"/>
        <form:hidden path="sheet[${status.count -1}].footer"/>
        <form:hidden path="sheet[${status.count -1}].operador"/>
        <form:hidden path="sheet[${status.count -1}].number"/>
        <form:hidden path="sheet[${status.count -1}].lines"/>
    </c:forEach>
    ...
</form:form>

I need to get back this list in the controller when the form is submitted. So in my controller I have a method with a parameter like this:

public String myMethod (@ModelAttribute("book") Book book, Model model){
    ...
}

The problem is that it doesn't fill the sheets list unless in the constructor of Book I add as much Sheet's as I want to get. The problem is that I don't know in advance the number of Sheets the book is going to have.

I think the problem is that in my method it instantiates Book which has a list of sheets with 0 elements. When it tries to access to sheets[0] the list is empty and it doen't add a Sheet. I've tried to create a getter method for the list with an index parameter (so it can create the element if it doesn't exists in the list like in Struts framework) like this one:

public Sheet getSheets(int index){
    if(sheets.size() <= index){
        Sheet sheet = new Sheet();
        sheets.add(index, sheet);
    }
    Sheet sheetToReturn = sheets.get(index);
    if(sheetToReturn == null){
        sheetToReturn = new Sheet();
        sheets.add(index, sheetToReturn);
    }
    return sheetToReturn;
}

but with this method the JSP doesn't work because sheets has an invalid getter.

What's the proper way of filling a list when you don't know the number of items in advanced?

Thanks

+1  A: 

This getter is indeed not going to work. With collections in EL, ${bean.list[0]} would roughly resolve to bean.getList().get(0), not to bean.getList(0) as you seem to expect.

You need to pass the size of the list as a request parameter as well and prepare the list accordingly. You can use JSTL fn:length() to get the size:

<input type="hidden" name="size" value="${fn:length(mybook.sheets)}">

(sorry, no Struts targeted example with form:hidden, I don't use it, but it should give you an idea)

When the size is set, then you can prepare the list as follows:

for (int i = 0; i < this.size; i++) {
    sheets.add(new Sheet());
}

That said, you can better use ${status.index} instead of ${status.count - 1}. See the LoopTagStatus API for all available methods.

BalusC
Thanks for your answer, though I think it would only work when size is populated before the list's elements. I'm not sure that Spring always populates items in the same order as they are in the form. On the other hand I think Spring's AutopopulatingList is a cleaner solution.
Javi
+1  A: 

If you make your list a lazy list (Apache Commons Collections LazyList or Spring's AutoPopulatingList) it will instantiate a new Sheet as a given list element at the moment you bind to it. Then you don't have to worry about how many items you've prepopulated the list with -- you can call list[17] on an empty list and it will be created on the fly and bound.

JacobM