ActionForms: Struts' bastard child
Folks that rag on Struts seem to point to ActionForms as one of its major design flaws. I've been slightly frustrated with ActionForms this week, but overall, I think they're a good thing. It's possible my ActionForm affection is misguided. The major reasons I like them is because I believe they allow me to do stuff that is not possible in other web frameworks. I definitely could be wrong though, so I'm hoping the other framework authors/users will speak up and say "My framework does that!" Specifically, I'm talking to the WebWork, Tapestry, JSF and Spring folks.
I do wish that I could throw my POJOs up to my UI, so I hope the following things are possible with the WTJS frameworks. It would simplify things if I didn't need to transform POJOs -> ActionForms (particularly with Hibernate).
- Validation and re-displaying the user's entered values. I love Struts' Validator. It's great how I can generate the validation.xml file with XDoclet and have a "required" struts.validator tag right next to a hibernate not-null="true" tag. Two questions:
1. Can any of the WTJS frameworks re-display the user's entered values? Specifically, back into the input fields where the user entered them? I think this is important for useability.
2. Do any of them have the ability to generate client and server-side validation, or at least declaratively write it in XML?
I'd love to find a way to hack the Validator to allow you to define validation rules for a POJO and then use an Interceptor to validate it. I don't like how Spring requires you to write YAJC (Yet Another Java Class) to do validation. - Handling checkboxes. The basic reason for the reset() method in ActionForms is to handle checkboxes. Since unchecked checkboxes don't send a value - there needs to be a way to set a boolean back to null. I'm sure all of the WTJS frameworks support checkbox handling, I just want to make sure - and frankly - I'd like to learn a little more about how each framework handles it.
I guess there's only two reasons I like ActionForms - the major one being the ability to specify (and generate) my client and server-side validation in XML. If I don't find this same slick feature in the other frameworks, I might have to do a bit of hacking to do the Interceptor with Validator thing - but hopefully I won't need to go there.
However, currently there is no Validation / Interceptor architecture like Struts. Unfortunately you'd have to hack that type of validation into your application. Considering Echo is based on Swing's Interfaces, it's going to inherit Swing's validation framework, which basically means that validation will occur in the actionListener method when a user clicks a button...
However, I can understand the power and need to externalize that kind of thing into the XML files... One person has suggested the use of commons-validation but no one has reported success either way. It really needs some sort of declarative framework though...
On a side note, I'm thinking that XDoclet is something that I seriously need to learn. :)
thx
Posted by mnickel on February 05, 2004 at 05:23 AM MST #
WebWork2 provides most of the features you're asking for.
1. Can WebWork display the original values back to the user?
Yes, you have the capability of doing this, but this isn't the default behavior. The default behavior is to highlight the field and ask the user to fill in the correct data. You can relatively easily modify the template that the ui tag uses so that it populates the field with the data the user entered.
2. Does WebWork have an XML validation framework?
Again, the answer is yes. Here's a small snippet that should give you a sense of what the validation looks like:
Posted by Matt Ho on February 05, 2004 at 06:36 AM MST #
Posted by Matt Ho on February 05, 2004 at 06:50 AM MST #
Posted by Matt Raible on February 05, 2004 at 10:23 AM MST #
Posted by Redmapper on February 05, 2004 at 01:17 PM MST #
I simply use one XDoclet to flag the POJO for Form generation. I can also use @struts.validator tags on the POJO to generate the validation.xml file. Furthermore, it's much easier to use an IDE with concrete ActionForms, than using casting and get("propertyname) that you have to do with DynaActionForms.
Posted by Matt Raible on February 05, 2004 at 02:32 PM MST #
Posted by Scott Mitchell on February 05, 2004 at 05:54 PM MST #
Posted by Kito D. Mann on February 05, 2004 at 06:07 PM MST #
Posted by Arron Bates on February 05, 2004 at 06:19 PM MST #
Posted by Jason Carreira on February 06, 2004 at 12:37 AM MST #
Posted by Erik Hatcher on February 06, 2004 at 01:51 AM MST #
Posted by Matt Ho on February 06, 2004 at 07:14 AM MST #
I think the real advantages of separate ActionForms are:
-The ActionForm can be easily shared between multiple Actions
-Enables the Action to be a singleton
Validation, etc, are all possible in other frameworks. Some simple spring examples just write directly to business objects, which is usually wrong if any errors could be generated. This causes data entered by the user to be lost.
-Paul
Posted by PSK on February 08, 2004 at 04:33 AM MST #
Posted by Jason Carreira on February 09, 2004 at 05:39 AM MST #
I think it centers around performance. Actions in struts are used, not just for handling form input, but also to enable flowcontrol to be kept in the struts-config.xml file. Since actions are singletons, there's no overhead of allocation or a pool lookup.
But.. I really agree with you, I think the benefits of singletons do not out-weigh their drawbacks. I'm never in an environment where the overhead of object allocation will make or break me. But I respect their desicion just the same...
I'm really exicted about picocontainer + webwork2 myself. ;)
Posted by PSK on February 09, 2004 at 11:29 PM MST #
Conversion between user-entered Strings and form object fields is done via registered PropertyEditors in Spring. The same PropertyEditors will also be used for displaying the form field values, converting back from the form object field type to a String. A set of standard editors is pre-registered; custom PropertyEditors can be registered in your command/form controller's "initBinder" method.
The recommended Spring strategy is to implement validation logic in a separate object, but note that this Validator is a business object that's not tied to web usage by any means! You write it for domain objects, not for web form objects. Alternatively, you can also implement validation logic in an "onBindAndValidate" method in your command/form controller class - no separate class necessary then, accepting the tradeoff that the logic is bound to the web then.
Regarding action/form objects: Spring controllers are servlet-style shared instances like Struts actions, but the command/form objects used are plain POJOs (typically existing domain objects) with either request or session scope. I do believe that shared controller instances have value, but I strongly object to having form objects that derive from an ActionForm base class.
For my taste, WebWork combines too many object roles in the action: It is controller, command/form object, validation errors holder, etc. Spring separates those object roles into individual objects. And as far as I can see, WebWork doesn't support form objects with session scope; it always binds to a new instance for each request. What about editing a Hibernate-persistent object that stores collection snapshots and possibly a version field? We need to bind to the *same instance* on re-submit here, for efficiency and detection of optimistic locking failures.
Posted by Juergen Hoeller on February 10, 2004 at 10:24 AM MST #
Posted by Juergen Hoeller on February 10, 2004 at 10:27 AM MST #
Posted by Jonathan Lehr on February 12, 2004 at 12:21 AM MST #
First we created a project-specific abstract base class that extends ActionForm, and implements the DynaBean interface. We added a Map to our form class to cache UI string values (both inbound and outbound), and implemented the DynaBean get() and set() methods to transparently access its values. We overrode the RequestProcessor such that prior to forwarding to the JSP, it invokes a method on the form that populates the Map of string values by recursively descending the object graph that begins at the form. Conversions are done on bean properties by instances of Formatter classes. Our framework provides a default set of bindings of Java types to Formatter classes, so that this stuff happens automagically, unless the developer specifies something other than the default (very rare in our application since we have custom value classes for money, percentages, etc., but quite easy to do, either through a Java API or XML).
The Map that is built models the structure of the object graph, so that references in the JSP look exactly like they would normally (e.g., <bean:write name="foo" property="bean.nestedBean.someProperty"/>). When Struts (using beanutils) binds inbound values, the beanutils code sees that the form is a DynaBean and invokes it's get() method to get the initial value in the keypath. We designed our implementation to lie about the underlying data types (telling beanutils that they're all Strings or arrays of Strings) to avoid ConvertUtils conversions.
We then added a bit of code to our RequestUtils processValidate() method to invoke a method on our form class that binds the values from the Map to the real objects. Our framework again finds the approriate Formatter classes by introspecting the property types (don't worry, we cache all this stuff, so the overhead is minimal). Any time a conversion error is encountered, the framework automatically adds an ActionError with an appropriate error message. If there are no conversion errors, the form calls the regular validation code.
This design allows us to use POJOs in our ActionForms, and automatically handles conversion errors and formatting. You can actually do an even simpler version of this with beanutils 1.7, by subclassing BeanUtilsBean and PropertyUtilsBean to allow values to be diverted to the Map of strings (DynaBean's a pretty big interface, so there's a lot more you have to do to use that approach, though it's arguably a more robust way to do it).
On the other hand, if you don't *have* to use Struts (a lot of projects mandate it), then by all means look at Tapestry. I haven't worked with it myself, but I have used WebObjects (which takes a similar approach) quite a bit, and it's one tenth the work/ten times the flexibility of doing stuff with *any* JSP-based framework.
Posted by Jonathan Lehr on February 12, 2004 at 12:24 AM MST #
Posted by sub4x on February 24, 2004 at 08:18 PM MST #
Posted by Eelco Hillenius on April 09, 2004 at 10:27 PM MDT #
Posted by Sudhir Nimavat on January 23, 2007 at 09:53 AM MST #
Posted by 203.88.149.218 on January 23, 2007 at 09:55 AM MST #
Posted by sudhir nimavat on January 23, 2007 at 09:56 AM MST #
Posted by 122.169.244.87 on August 19, 2008 at 06:04 AM MDT #