I've released a Struts Resume sample application that makes heavy use of Struts, XDoclet, Ant and Hibernate to automate much of the build/test and database-generation process.
While going through your resume code to learn how to port hibernate into my polls app, I noticed the following:
Usually, I have my actions "do the walk" between the view and the model, ie, I have them retrieving form beans (view/controller, sort of) and populating buz beans (model), before calling the persistence layer to handle them beans.
However, you pass the form beans directly to the persistence layer and have them populated there.
Since form beans are kind of "undefined" hybrids, I think your approach uses them as more like model entities.
I kinda of like that, and I was thinking what are the main disadvantages of using form beans as model beans, since despite being generally defined as a controller entity, they can also play the bean role quite convincingly.
I'm not suggesting this should become a standard practice, because the design of some applications might not allow it. However, most of the time I've got beans that are either stripped replicas (without the validation) of their form bean equivalent, possibly with different field types. Why keep them both?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I don't believe I'm doing this, but rather I'm passing Forms to my "services" layer and they're transformed into POJOs using BeanUtils.copyProperties. Please let me know if this is not happening and I'm passing a form all the way to the persistence layer.
Thanks,
Matt
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Indeed that is the case, Matt -you've got a services layer in-between. Sorry, I (wrongly) thought of it as being part of the persistence layer.
Anyways, although I extrapolated wrongly from your code, my question still remains. Why couldn't we use form beans as model beans? I am sure the fields types can't be a good enough argument because it can be easier to overcome this rather than writing yet another class, yet more properties, yet more getter and setters, ...
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Ok, this has been very enlightening!
Please, bear in mind that I am not blaming nor criticizing any approach taken -I merely wish to understand the pro's and con's of using form beans as normal beans.
I am not partial to the form bean myself- I am partial to a more simple solution. I obviously agree there should be a bean that converts the back-end/datasource language into the buz/presentation language.
I agree with you that validation is also a requirement, whether if it's done at the request level or at the bean level.
However, as interesting as it may sound, validation at the request level does not fill in all the gaps, since the bean's existence might extend beyond the life-cycle of the request. That's is also what happens when we separate form beans and beans, as you pointed out. And as you also said, validation should always be there, just in case. There can be a situation where you validate user input at the request level, but your application might also modify data internally -these changes may require the same validation preventions. Hence, validation should be, as you said, at the bean level.
So, these two requirements seriously convince me that form beans are the ideal candidate to pass back and forth and make the connection between the presentation and the model layer.
Also, I'll have a look at the struts source to check on this, but I was under the impression that struts maintains a pool of its resources internally -if that is the case, form beans are even more so the better option!
I'm gonna play with this approach after I finish integrating hibernate ;-)
That is, when I'm done with my 12hour coding marathons :-(
That is, unless you provide me a final argument against it
Cheers
jorge
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I think we agree that there is often a role for a Data Entry Object in many applications -- a DTO with presentation layer helper methods. But the ActionForm has been specifically designed to discourage its use beyond the entry-validatate-entry loop. (Not an interface, requires web semantics in its signatures.)
One approach is to define an interface for your DEO/DTO, and have the ActionForm implement that. In this way, your non-Struts code can refer to the interface rather than "ActionForm".
The real drawback of using ActionForms in the business layer is all input comes in as Strings and most of us want to re-present bad input for correction. If you use other types on your ActionForm, and want to re-present input, you can't use the Struts tags out-of-the-box.
So, to use the Struts tags and redisplay input, every field must have a String property. If you define a String property for every field, you might as well have two objects. (Been there, done that.) If you define String properties for only non-String fields, you become confused about which property to call when. (Been there, done that).
If we use a validator technology to vet the request, and use tags that will look to the request when a formbean property is null, then needing to define a property to buffer bad input goes away. (The request is our buffer.)
This opens the door to using typed data on ActionForms, which means ActionForms can implement an arbitrary business interface, and that you could pass a (validated) ActionForm directly to the business layer via its Interface.
Meanwhile, we been stripping the web and Struts semantics from a number of our core classes (Validator, Messages), so we can use the same tools on the web and business layers. Struts uses the struts-validator, your business layer use the commons-validator, but both could be working from the same XML document (at least in theory).
So, the two missing links are (1) using the request as input to the struts-validator and (2) Struts tags/Velocity macros that look to the request when a form property is null.
-T.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
The classic argument is that ActionForms can't use native types, since they can't replicate non-String input. Though, I've been wondering why we just don't have the tags (or whatever) check the request if a property is null, and use the request for the input buffer instead. [I might try this in Velocity.]
The second argument is security. Populating a method on a business bean might fire a business process that we aren't ready to execute yet. Good argument, but limited applicability.
The third argument is validation. But I'm thinking validation is a perfectly reasoanble thing for an "entity object" (in the Hibernate sense) to do. Any bean that might be populated from an external resource, whether it is a database or HTTP request, should be able to validate itself, since there's no telling what happened to its data between sessions. (Which speaks to point #2 - a good business object should not execute critical methods if its state is invalid.)
The fourth argument is composition. Often a single HTML form is made of several objects. These are more easily represented by a single object than multiple objects. Nesting object is an option, but the nested syntax confuses other players, like JavaScript. Ant he more objects you nest, the more security issues you might raise.
I'm still kinda sold on the last one. I'm thinking a "data entry object" make senses in most application, to encapsluate the input fields and provide presentation helper methods. In practice, it's a coarse-grained, denormalized transfer object, where userName equates to user.Name. And this could also be a DynaBean generated using an Xdoclet approach.
What I'm thinking about now is a fancy version of BeanUtils.Populate that would actually automatically map userName to user.Name if you passed it a set of target beans. It might also take a configuration to map the coarse names to the fine names, they way Hibernate maps properties to columns.
-T.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I'm still hesitant, though.
Very often the projects I'm involved with have some kind of CRUD whatever-entity management. If the form-bean IS the bean, I could write generic actions to use across projects without any loss of functionality and with minimal needs to customise.
And certainly there are more potentially generic actions other than CRUD actions.
Of course there are alternatives, and I can just mention the use of a services layer such as the one Matt uses in his resume app.
Some time ago I've also used the "parameter" option on the struts-config mapping to refer to the type of some dynamic entity to be used by generic actions. I quit using this method when, most than not, I needed the "parameter" option for, well, what is supposed to be used for :-)
Am I being blind here? Do generic actions justify the use form-beans between the controller and the model? Is it "feasible" designwise or will it become a too-strict compromise? Is a services layer a better approach (though, still adding another layer)?
jorge
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Just an add-on to my previous post. I understand your arguments and I am certainly drawn back by at least the web-semantics signatures. I think the fact that form-beans can only handle Strings can be overcome easily with mechanism like BeanUtils but used in a different layer.
But it seems soooo irresistable to be able to do something like:
On an application that keeps some type of users that can manage their online bookmarks, for instance. This takes full advantage of the Struts powerful dynamic mechanisms, I think.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I've released a Struts Resume sample application that makes heavy use of Struts, XDoclet, Ant and Hibernate to automate much of the build/test and database-generation process.
Download at: http://sourceforge.net/project/showfiles.php?group_id=49385&release_id=143601
While going through your resume code to learn how to port hibernate into my polls app, I noticed the following:
Usually, I have my actions "do the walk" between the view and the model, ie, I have them retrieving form beans (view/controller, sort of) and populating buz beans (model), before calling the persistence layer to handle them beans.
However, you pass the form beans directly to the persistence layer and have them populated there.
Since form beans are kind of "undefined" hybrids, I think your approach uses them as more like model entities.
I kinda of like that, and I was thinking what are the main disadvantages of using form beans as model beans, since despite being generally defined as a controller entity, they can also play the bean role quite convincingly.
I'm not suggesting this should become a standard practice, because the design of some applications might not allow it. However, most of the time I've got beans that are either stripped replicas (without the validation) of their form bean equivalent, possibly with different field types. Why keep them both?
I don't believe I'm doing this, but rather I'm passing Forms to my "services" layer and they're transformed into POJOs using BeanUtils.copyProperties. Please let me know if this is not happening and I'm passing a form all the way to the persistence layer.
Thanks,
Matt
Indeed that is the case, Matt -you've got a services layer in-between. Sorry, I (wrongly) thought of it as being part of the persistence layer.
Anyways, although I extrapolated wrongly from your code, my question still remains. Why couldn't we use form beans as model beans? I am sure the fields types can't be a good enough argument because it can be easier to overcome this rather than writing yet another class, yet more properties, yet more getter and setters, ...
Initially, it was because most model beans couldn't cope with things like validation and it was downright dangerous to use them for HTML data entry.
Of course, over the last three years, a lot of that has changed and new technologies are available.
So, I'll do you one better -- why do we need form beans at all?
Why not apply the validator technology to the request directly? (missing == null).
If we know we have a valid set of properties in the request (which is to say a map), we can just use that to populate the model bean.
-Ted.
Ok, this has been very enlightening!
Please, bear in mind that I am not blaming nor criticizing any approach taken -I merely wish to understand the pro's and con's of using form beans as normal beans.
I am not partial to the form bean myself- I am partial to a more simple solution. I obviously agree there should be a bean that converts the back-end/datasource language into the buz/presentation language.
I agree with you that validation is also a requirement, whether if it's done at the request level or at the bean level.
However, as interesting as it may sound, validation at the request level does not fill in all the gaps, since the bean's existence might extend beyond the life-cycle of the request. That's is also what happens when we separate form beans and beans, as you pointed out. And as you also said, validation should always be there, just in case. There can be a situation where you validate user input at the request level, but your application might also modify data internally -these changes may require the same validation preventions. Hence, validation should be, as you said, at the bean level.
So, these two requirements seriously convince me that form beans are the ideal candidate to pass back and forth and make the connection between the presentation and the model layer.
Also, I'll have a look at the struts source to check on this, but I was under the impression that struts maintains a pool of its resources internally -if that is the case, form beans are even more so the better option!
I'm gonna play with this approach after I finish integrating hibernate ;-)
That is, when I'm done with my 12hour coding marathons :-(
That is, unless you provide me a final argument against it
Cheers
jorge
I think we agree that there is often a role for a Data Entry Object in many applications -- a DTO with presentation layer helper methods. But the ActionForm has been specifically designed to discourage its use beyond the entry-validatate-entry loop. (Not an interface, requires web semantics in its signatures.)
One approach is to define an interface for your DEO/DTO, and have the ActionForm implement that. In this way, your non-Struts code can refer to the interface rather than "ActionForm".
The real drawback of using ActionForms in the business layer is all input comes in as Strings and most of us want to re-present bad input for correction. If you use other types on your ActionForm, and want to re-present input, you can't use the Struts tags out-of-the-box.
So, to use the Struts tags and redisplay input, every field must have a String property. If you define a String property for every field, you might as well have two objects. (Been there, done that.) If you define String properties for only non-String fields, you become confused about which property to call when. (Been there, done that).
If we use a validator technology to vet the request, and use tags that will look to the request when a formbean property is null, then needing to define a property to buffer bad input goes away. (The request is our buffer.)
This opens the door to using typed data on ActionForms, which means ActionForms can implement an arbitrary business interface, and that you could pass a (validated) ActionForm directly to the business layer via its Interface.
Meanwhile, we been stripping the web and Struts semantics from a number of our core classes (Validator, Messages), so we can use the same tools on the web and business layers. Struts uses the struts-validator, your business layer use the commons-validator, but both could be working from the same XML document (at least in theory).
So, the two missing links are (1) using the request as input to the struts-validator and (2) Struts tags/Velocity macros that look to the request when a form property is null.
-T.
<<breaker, breaker>>
> Why keep them both?
The eternal question!
The classic argument is that ActionForms can't use native types, since they can't replicate non-String input. Though, I've been wondering why we just don't have the tags (or whatever) check the request if a property is null, and use the request for the input buffer instead. [I might try this in Velocity.]
The second argument is security. Populating a method on a business bean might fire a business process that we aren't ready to execute yet. Good argument, but limited applicability.
The third argument is validation. But I'm thinking validation is a perfectly reasoanble thing for an "entity object" (in the Hibernate sense) to do. Any bean that might be populated from an external resource, whether it is a database or HTTP request, should be able to validate itself, since there's no telling what happened to its data between sessions. (Which speaks to point #2 - a good business object should not execute critical methods if its state is invalid.)
The fourth argument is composition. Often a single HTML form is made of several objects. These are more easily represented by a single object than multiple objects. Nesting object is an option, but the nested syntax confuses other players, like JavaScript. Ant he more objects you nest, the more security issues you might raise.
I'm still kinda sold on the last one. I'm thinking a "data entry object" make senses in most application, to encapsluate the input fields and provide presentation helper methods. In practice, it's a coarse-grained, denormalized transfer object, where userName equates to user.Name. And this could also be a DynaBean generated using an Xdoclet approach.
What I'm thinking about now is a fancy version of BeanUtils.Populate that would actually automatically map userName to user.Name if you passed it a set of target beans. It might also take a configuration to map the coarse names to the fine names, they way Hibernate maps properties to columns.
-T.
Thanks Ted! Those were very good points you made!
I'm still hesitant, though.
Very often the projects I'm involved with have some kind of CRUD whatever-entity management. If the form-bean IS the bean, I could write generic actions to use across projects without any loss of functionality and with minimal needs to customise.
And certainly there are more potentially generic actions other than CRUD actions.
Of course there are alternatives, and I can just mention the use of a services layer such as the one Matt uses in his resume app.
Some time ago I've also used the "parameter" option on the struts-config mapping to refer to the type of some dynamic entity to be used by generic actions. I quit using this method when, most than not, I needed the "parameter" option for, well, what is supposed to be used for :-)
Am I being blind here? Do generic actions justify the use form-beans between the controller and the model? Is it "feasible" designwise or will it become a too-strict compromise? Is a services layer a better approach (though, still adding another layer)?
jorge
Just an add-on to my previous post. I understand your arguments and I am certainly drawn back by at least the web-semantics signatures. I think the fact that form-beans can only handle Strings can be overcome easily with mechanism like BeanUtils but used in a different layer.
But it seems soooo irresistable to be able to do something like:
<action path="/process/crud"
type="org.crud.Action"
name="usersFormBean"
parameter="action">
</action>
<action path="/process/crud"
type="org.crud.Action"
name="bookmarksFormBean"
parameter="action">
</action>
On an application that keeps some type of users that can manage their online bookmarks, for instance. This takes full advantage of the Struts powerful dynamic mechanisms, I think.
Ooopss, sorry. Those last two actions should be:
<action path="/process/crud/users"
type="org.crud.Action"
name="usersFormBean"
parameter="action">
</action>
<action path="/process/crud/bookmarks"
type="org.crud.Action"
name="bookmarksFormBean"
parameter="action">
</action>
Where org.crud.Action is an action extending the LookupDispatchAction with CRUD methods.