aspose file tools*
The moose likes Struts and the fly likes Collections and Struts... Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Spring in Action this week in the Spring forum!
JavaRanch » Java Forums » Frameworks » Struts
Bookmark "Collections and Struts..." Watch "Collections and Struts..." New topic
Author

Collections and Struts...

Corey McGlone
Ranch Hand

Joined: Dec 20, 2001
Posts: 3271
I've run across a problem in the last couple applications I've worked on using Struts and I'm wondering if there's a better solution than what I have been using.

The problem I face is that I have a number of records in the database that all need to be displayed to a user. The user can then look at those records and edit any, all, or none of them. When the page is submitted, I need to take those changes and save them to the database.

In order to facilitate this in Struts, I've been using a Collection of objects in my form beans and then populating my JSP using the nested:iterate tag. That seems to work just fine.

However, it's reading the data back in that gives me trouble. It doesn't seem that Struts will create the objects from scratch - if they don't exist in the form bean, they simply aren't populated with the updated data. To get around this, I've been having my "preparation action" (the one that reads the data from the database) and my "submission action" (the one that stores the data back to the database) using the same form bean and I've set that form bean to use Session scope.

That approach seems to work, but I don't like keeping that sort of data in the session - it just doesn't seem appropriate.

Anyone know a better way to tackle this problem?

Thanks,
Corey


SCJP Tipline, etc.
Jason Menard
Sheriff

Joined: Nov 09, 2000
Posts: 6450
What I usually do is use a what I call a Form Assembler object to move data back and forth between the form and my model. My model object will typically contain a property which is a collection of other objects. For example, let's say I have a Library object which contains a List of Book objects.

Given the use case you describe, I would have a LibraryFormAssembler which might look like this (maybe you have a FormAssembler interface to go along with it):

LibraryFormAssembler
--------------------
+assembleForm(Form, Object) : void
+assembleObject(Object, Form) : void



LibraryForm


So if I wanted to view the List of Books, I might have this action

ViewBookListAction


Edit the list (I'll assume you keep your Library object in session on this one)...

EditListAction


Add a blank book entry to the list of books so that it may be edited...

AddBookAction


I could go on but I'm sure you probably get the gist by now. The point is I rebuild the form as needed using the assemblers. This makes sure that I always have a BookForm object to coincide with every Book object in my Library, which should alleviate the problem you have been running into, if I undertand correctly.
[ June 21, 2005: Message edited by: Jason Menard ]
Merrill Higginson
Ranch Hand

Joined: Feb 15, 2005
Posts: 4864
An approach that I sometimes use is to utilize the reset() method of the form bean. It works like this:
  • Have your preparation action save the list size as a session attribute.
  • Override the method reset() in your action form to check if the list is empty. If it is, get the size from the session, and create a list of empty beans the same size as your original list.
  • If there are attributes that are in each bean that aren't displayed, put them in hidden fields in the jsp.
  • When the form is submitted, Struts will be able to use the indexed getters and setters to set the data in the bean, provided you have named the properties correctly.

  • Using this approach you avoid storing a large amount of data in the session, and you can still use collections of beans in your form.


    Merrill
    Consultant, Sima Solutions
    Corey McGlone
    Ranch Hand

    Joined: Dec 20, 2001
    Posts: 3271
    Thanks a lot for the suggestions. However, I've got a new wrinkle to add, if I may...

    In an earlier case, I needed to grab data from a database and display that collection to the user. The user could then edit that data and resubmit it. The key here was that the number of elements that I'd be displaying would always be exactly the same as the number of element the user would be submitting. The user had no way to add or delete elements - only edit them and resubmit them. They were added and deleted through a different process.

    In the case I'm now faced with, I may have some data to show the user originally, and I may not. The first time the user accesses the screen, there will not be any data to display. I'd like to use DHTML to allow the user to add new elements to add new elements to the form from the client side. Then, when the user is done, the user can submit those newly created elements. So, the trick here is that there are 0 elements going out and many elements coming back in. So, ahead of time, I have no idea how many elements to expect.

    Honestly, the only way I can think to handle such a case is to do my own object population, rather than relying on Struts to do it for me. In that case, I can look through the request for values and create objects as needed. Anyone have a better approach to this problem?

    Thanks.
    Jason Menard
    Sheriff

    Joined: Nov 09, 2000
    Posts: 6450
    I'd like to use DHTML to allow the user to add new elements to add new elements to the form from the client side.

    Personally, I avoid doing this precisely because of the situation you are facing. That said, there are a few opitons:

    1. Don't do it. Every time they "add" a new element your app would call an action that would do something like add a new empty object to your model's collection, then assemble the form based on the current state of the model. When you redisplay back to the user, he now has his blank element he can fill in and you have a one-to-one mapping of collection objects with your model. This is my preferred method.

    2. Don't use an ActionForm. Have your Action (or a helper object used by the Action) parse through the request manually and decide how to populate your model. This one's pretty ugly imho and I'd avoid it.

    3. Extend RequestProcessor and override processPopulate(). Examine the request and manipulate your ActionForm's collections as needed. Again, not my preferred option, hard to do generically so that it handles all ActionForms (say hello to my friend the Java Reflection API), but it is an opiton.

    4. A combination of #3 along with having your ActionForms implement an interface which would make it easier for the RequestProcessor to modify your collections, but delegating the specifics to the ActionForm. For example maybe give your ActionForms a method name like addToCollection(String collectionName). Still, I don't particularly care for this option either.

    Personally, I'd strongly advocate option 1.
     
    I agree. Here's the link: http://aspose.com/file-tools
     
    subject: Collections and Struts...