Win a copy of Re-engineering Legacy Software this week in the Refactoring forum
or Docker in Action in the Cloud/Virtualization forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Automatic Population of Indexed Fields

 
Corey McGlone
Ranch Hand
Posts: 3271
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hey folks,

I'm trying to get Struts to automatically populate some data for me from an web form and it's just not working. What I have is this...

A form bean, called CollaborationForm, which has an ArrayList object called comments. The point of this form is for multiple users to collaborate on the data they had entered previously, so there will be more than one comment to display. So, my form bean looks something like this (this is a bit simplified, but it's close):



Now, that ArrayList, allComments, contains nothing but Comment objects. A Comment object isn't very complicated - it only contains a few fields that are all related: the comment, the username of the person who wrote that comment, and whether or not that comment should be saved. So the Comment object looks like this:



Now, in my JSP file, I can easily display all of the comments by doing this:



That prints all of my comments just the way I want. The real problem is when the user submits the form and Struts tries to take this form data and populate my form bean.

The method getAllComments() is being invoked, which returns an empty ArrayList() (because the form bean has not yet been populated). Shortly after that happens, I get an IndexOutOfBoundsException. I assume that Struts is trying to get a given Comment object out of the empty list - causing the exception.

If I add a constructor to my form bean that looks like this:



Then everything works. Of course, this only works if my constructor adds the right number of Comment objects to the ArrayList. Unfortunately, I have no idea how many comments there might be - so this isn't really a solution. I really did it just to help diagnose what's going on.

So any ideas? I'm quite perplexed on this one.

Thanks,
Corey
[ October 12, 2005: Message edited by: Corey McGlone ]
 
Vani Bandargal
Ranch Hand
Posts: 82
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
try this getter

let me know if this works or not
[ October 12, 2005: Message edited by: Mark Spritzler ]
 
Mark Spritzler
ranger
Sheriff
Posts: 17278
6
IntelliJ IDE Mac Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Corey, Corey, Corey.



So if you pass and index to this method that is larger than the size() -1 then you will get an indeax out of bounds exception.

Now to my real comments.

1. Follow Sun's Coding Standards.
2. Put curly braces after the if statement and after the return new Comment(). Second if the index is <= size() you can get the same error because arrays are zero based.
3. Do you really mean >= size()? Because I would assume you would want to pass a valid index that exists, and that second return statement will only run if the index passed is too high for the number of elements in the Array.
4. Why use .toArray()[], when you can just use the get() method of ArrayList.

Mark
 
Junilu Lacar
Bartender
Pie
Posts: 7316
45
Android Eclipse IDE IntelliJ IDE Java Linux Mac Scala Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Corey,

The problem is probably in the setAllComment(int index) method. First check (index >= allComments.size()). If it is, use a loop to add the appropriate number of new Comments. Then you can safely return allComments.get(index). You also might want to write a method resizeAllComments(int newSize) and call it from both the getAllComment and setAllComment methods when the index is out of bounds.
 
Chi Hang Chiu
Greenhorn
Posts: 5
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Junilu,

You are right. I got your suggestion and create a working example. Thks.

master bean:
public final class A extends ActionForm {
private ArrayList allB = new ArrayList();


public ArrayList getAllBList() {
return allB;
}


public void setAllBList(ArrayList list) {
allB = list;
}


public B getAllB(int index) {
while (index >= allB.size()) {
allB.add(new B());
}
return (B) allB.get(index);
}


public void setAllB(int index, B in) {
if (index >= allB.size()) {
int i = allB.size();
do {
allB.add(new B());
} while (index >= ++i);
}
allB.set(index, in);
}
}

Detail Bean:
public final class B extends ActionForm {
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
private String field = sdf.getInstance().format(new Date());


/**
* Returns the value of field.
*
*@return The field value
*/
public String getField() {
return field;
}


/**
* Sets the value of field.
*
*@param field The value to assign field.
*/
public void setField(String field) {
this.field = field;
}

}

Simple Action:
public final class AAction extends Action {

public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {

A f = (A) form;
B b = new B();
ArrayList al = f.getAllBList();
f.setAllB(al.size(), b);
return (mapping.findForward("input"));
}
}

Simple JSP:

<nested:iterate id="allB" property="allBList" name="AForm">
<nested:text indexed="true" property="field" name="allB"/>
</nested:iterate>

Originally posted by Junilu Lacar:
Corey,

The problem is probably in the setAllComment(int index) method. First check (index >= allComments.size()). If it is, use a loop to add the appropriate number of new Comments. Then you can safely return allComments.get(index). You also might want to write a method resizeAllComments(int newSize) and call it from both the getAllComment and setAllComment methods when the index is out of bounds.
 
Junilu Lacar
Bartender
Pie
Posts: 7316
45
Android Eclipse IDE IntelliJ IDE Java Linux Mac Scala Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Now that I think about it with a clearer mind (previous post was made early this morning, as you can see, so excuse the brain fart), Struts is probably calling the getAllComment(int index) to get the bean it needs to populate with values from the request parameters. The basic solution is still the same though: you need to resize the allComments list.
 
Corey McGlone
Ranch Hand
Posts: 3271
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hey gang,

I really appreciate the comments, but I'm still having issues. I've updated my method to look like this:



However, I'm still getting the IndexOutOfBoundsException. I should have mentioned it earlier, but my getAllEncounterComment(int index) method isn't actually being called. I've put a breakpoint in that method and it never gets hit. Rather, Struts invokes getAllEncounters() and then throws the exception. According to the stack trace, the exception is being tossed in:

org.apache.commons.beanutils.PropertyUtils.getIndexedProperty(PropertyUtils.java:521)

Any more ideas?

For what it's worth, here's a bit from the stack trace:


[ October 13, 2005: Message edited by: Corey McGlone ]
 
Corey McGlone
Ranch Hand
Posts: 3271
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ok, I think I've found the solution, thanks to this article.

The indexed accessor method needs to match, in name, with the "ID" field of the logic:iterate tag. However, looking back at my original code, my "ID" field actually says allComments, not allComment, so it wasn't hitting my indexed accessor, at all. Rather, it must have been retrieving the entire list (which was empty) and then trying to access the individual object within that list on its own, causing the IndexOutOfBoundsException.

So, anyway, it appears to be working, now that I've changed my JSP to look like this:



For some reason, the checkbox doesn't seem to be populating properly, but I'll look into that. For now, I'm just happy to see that my bean is populating properly.

Thanks again for the help, everyone.
 
Corey McGlone
Ranch Hand
Posts: 3271
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I took a quick look at the checkboxes and I can't understand why they're not populating properly. I'm testing with 2 comments in my list. So, based on that, the "setSave" method on my Comment object should be invoked twice - once for each Comment. However, setSave is being invoked only once. The other property methods, setComment and setIdentifiedBy, are being invoked twice, once with each value. Any ideas why my setSave method (which stores the property of the checkbox) would be called only once? It makes no sense to me.
 
Karthik Jay
Greenhorn
Posts: 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Corey,
Did you find solution to your problem?.

All,
I have strange problem in my struts page. I have 10 text input box but last 2 text are not getting saved. Its returning null all the time. Any help would really be appreciated. Thanks.

<TABLE id="tblHeaderVBY" border="0" width="100%" cellpadding="0"
cellspacing="0" nowrap>
<THEAD>
<TR valign="middle">
<TD nowrap width="40%">Attribute Name</TD>
<TD nowrap width="15%">Default Value</TD>
<TD nowrap width="15%">Behavior Code 1</TD>
<TD nowrap width="15%">Behavior Code 2</TD>
<TD nowrap width="15%">Behavior Code 3</TD>
</TR>
</THEAD>
<TR>
<TD align="left" width="40%" style="a11">attr1<INPUT
type="hidden" name="attr[0].attributeName" value="attr1"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[0].defaultValue" size="10" value=""></TD>

<TD align="left" width="15%"><SELECT
name="attr[0].behaviorCD1">
<OPTION value=""></OPTION>
<OPTION value="1" selected="selected">Value1</OPTION>
<OPTION value="2">Value2</OPTION>
</SELECT></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[0].behaviorCD2" size="10" value="2"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[0].behaviorCD3" size="10" value="0"></TD>
</TR>

<TR>
<TD align="left" width="40%" style="a11">attr2<INPUT
type="hidden" name="attr[1].attributeName" value="attr2"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[1].defaultValue" size="10" value=""></TD>

<TD align="left" width="15%"><SELECT
name="attr[1].behaviorCD1" class="formtext">
<OPTION value=""></OPTION>
<OPTION value="1">Value1</OPTION>
<OPTION value="2">Value2</OPTION>
<OPTION value="3" selected="selected">Value3</OPTION>
</SELECT></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[1].behaviorCD2" size="10" value="2"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[1].behaviorCD3" size="10" value="0"></TD>
</TR>

<TR >

<TD align="left" width="40%" style="a11">attr3<INPUT
type="hidden" name="attr[2].attributeName" value="attr3"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[2].defaultValue" size="10" value=""></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[2].behaviorCD1" size="10" value="0"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[2].behaviorCD2" size="10" value="0"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[2].behaviorCD3" size="10" value="0"></TD>
</TR>

<TR >

<TD align="left" width="40%" style="a11">attr4<INPUT
type="hidden" name="attr[3].attributeName"
value="attr4"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[3].defaultValue" size="10" value=""></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[3].behaviorCD1" size="10" value="0"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[3].behaviorCD2" size="10" value="0"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[3].behaviorCD3" size="10" value="0"></TD>
</TR>

<TR >

<TD align="left" width="40%" style="a11">attr5<INPUT
type="hidden" name="attr[4].attributeName"
value="attr5"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[4].defaultValue" size="10" value=""></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[4].behaviorCD1" size="10" value="0"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[4].behaviorCD2" size="10" value="0"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[4].behaviorCD3" size="10" value="0"></TD>
</TR>

<TR >

<TD align="left" width="40%" style="a11">attr6<INPUT
type="hidden" name="attr[5].attributeName" value="attr6"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[5].defaultValue" size="10" value=""></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[5].behaviorCD1" size="10" value="0"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[5].behaviorCD2" size="10" value="0"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[5].behaviorCD3" size="10" value="0"></TD>
</TR>



<TR >



<TD align="left" width="40%" style="a11">attr7<INPUT
type="hidden" name="attr[6].attributeName" value="attr7"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[6].defaultValue" size="10" value=""></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[6].behaviorCD1" size="10" value="0"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[6].behaviorCD2" size="10" value="0"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[6].behaviorCD3" size="10" value="0"></TD>
</TR>



<TR >



<TD align="left" width="40%" style="a11">attr8<INPUT
type="hidden" name="attr[7].attributeName" value="attr8"></TD>

<TD align="left" width="15%"><SELECT
name="attr[7].defaultValue" class="formtext">
<OPTION value=""></OPTION>
<OPTION value="Value1">Value1</OPTION>
<OPTION value="Value2">Value2</OPTION>
<OPTION value="Value3">Value3</OPTION>
</SELECT></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[7].behaviorCD1" size="10" value="0"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[7].behaviorCD2" size="10" value="0"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[7].behaviorCD3" size="10" value="0"></TD>
</TR>

<TR >

<TD align="left" width="40%" style="a11">attr9<INPUT
type="hidden" name="attr[8].attributeName" value="attr9"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[8].defaultValue" size="10" value=""></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[8].behaviorCD1" size="10" value="0"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[8].behaviorCD2" size="10" value="0"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[8].behaviorCD3" size="10" value="0"></TD>
</TR>

<TR>

<TD align="left" width="40%" style="a11">attr10<INPUT
type="hidden" name="attr[9].attributeName" value="attr10"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[9].defaultValue" size="10" value=""></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[9].behaviorCD1" size="10" value="0"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[9].behaviorCD2" size="10" value="0"></TD>

<TD align="left" width="15%"><INPUT type="text"
name="attr[9].behaviorCD3" size="10" value="0"></TD>
</TR>

</TABLE>
[ April 09, 2006: Message edited by: Karthik Jay ]
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic