This week's book giveaway is in the OCAJP 8 forum. We're giving away four copies of OCA Java SE 8 Programmer I Study Guide and have Edward Finegan & Robert Liguori on-line! See this thread for details.
A coworker of mine came to me with an issue he's havign with Struts and, unfortunately, the solution we came up with isn't particularly elegant. I was wondering if anyone here might have a better solution. Here's the situation:
1. The user goes to a particular page in a web application. From this page, the user can add new calendar events or edit existing ones. If the user wishes to save those changes, they can press a save button. In such a case, Struts creates a new form bean with the new values and that data can be stored. Everything is great.
2. While looking at the events of one day, the user can click on another day - a request is made to the application to retrieve the events for that day. The exact same form is redrawn with a list of events for another day.
This is where the problem comes in.
Each day is using the exact same form and the same form bean. Therefore, when the user goes from one day to the next, Form A requests Form A again, just with different parameters (a new date).
Struts sees this request and creates a new form bean for it. It then tries to populate that form bean, which it does very well because the reuqest came from the same form. This is what we don't want to happen. When the form is redisplayed to the user, the data from the previous day's event is still in the form fields.
Our best solution is to write a reset method for his form bean, but there are a few issues with that solution.
1. We'll have to invoke it explicitly in the Action class because, I believe, the reset method is invoked by Struts prior to the repopulation of the Form Bean. Therefore, if we counted on Struts to invoke it, we'd be no better off.
2. When we invoke it explicitly, we'd have to check to see if the user pressed "Save" or not. If the user did, we don't want to reset the form bean, if the user did not, we do. This just seems rather clumsy.
3. We are planning on writing a reset method that uses reflection to invoke each setter method our form bean has. This is appealing because, as we add features (additional form components), we don't want to have to update our reset method constantly. On the other hand, I don't particularly like using reflection - it always feels like some sort of hack.
So, anyway, that's what we came up with and, while I think it will work, I'm not particularly pleased with the solution. Anyone have any better ideas that might work?
If I'm understanding things correctly, it looks like part of the problem might be that you are having one Action do too many things. For example, you said that "we'd have to check to see if the user pressed "Save" or not." "Save" should certainly be a discrete Action that you shouldn't have to explicitly check for. In other words, pressing "Save" should call some kind of a Save Action.
It's easy to run into these kind of problems when you start having "Super Actions" that try to do everything. Any separate Action that a client is able to perform should be it's own Action class, or at least a discrete method in some type of DispatchAction.
So if you go ahead and have discrete actions (or methods within a DispatchAction) for every action a user may take, it should be very clear when you need a form reset, saved, or otherwise populated.
As far as "resetting" a form, another thing you can do if you feel it's appropriate is to instantiate a new ActionForm of the appropriate type and set it to the proper scope using the getAttribute() method from ActionMapping. For example, assuming your ActionForm is in request scope:
Of course, whether or not you feel this is appropriate will be dependant on your application, but it's nice to know this option is there.
The default implementation does nothing. In practice, the only properties that need to be reset are those which represent checkboxes on a session-scoped form. Otherwise, properties can be given initial values where the field is declared.
So I guess the question is, do you really need reset(), or do you just need the initial values of your properties for a request-scope form? This could be achieved simply by instantiating a new ActionForm as I demonstrated above.
HTH [ December 28, 2004: Message edited by: Jason Menard ]
As Jason hinted, the reset method is not intended to be used the way you plan to use it. You should instead write some kind of init() or clear() method to clear the values of the form. Call this from the appropriate action dispatching method that Jason suggested and you should be able to control the initialization of your form properties without resorting to all the ugliness you have planned to do in the reset() method.
As for using reflection, I would suggest you use org.apache.commons.beanutils.BeanUtils instead of writing your own "utility" from scratch.
Originally posted by Jason Menard: If I'm understanding things correctly, it looks like part of the problem might be that you are having one Action do too many things. For example, you said that "we'd have to check to see if the user pressed "Save" or not." "Save" should certainly be a discrete Action that you shouldn't have to explicitly check for. In other words, pressing "Save" should call some kind of a Save Action.
What would be the best way to implement this? Whether they click the Save button or a different date to view, the same form is being submitted. As such, the same "Action" is being executed - whatever is defined within the FORM tag.
CM: Whether they click the Save button or a different date to view, the same form is being submitted.
You can add an "action" property to your form and query that property to see what the user clicked and dispatch the request to the appropriate method in your Action class. Or you could use a DispatchAction to automate this, per Jason's suggestion.