|
From: Daniel M. <mi...@pa...> - 2004-05-12 02:40:14
|
Recently while browsing the Help list (man do I still have a life or not?) I came across this post: https://sourceforge.net/forum/message.php?msg_id=2564738 It got me thinking about a potential problem with Spring MVC. Spring MVC allows the user to bind the submit request directly to a persistent object (assume that the command object has been loaded using a Hibernate DAO in formBackingObject()). This eliminates a lot of code needed to transfer data from the form (i.e. Struts ActionForm) to the persistent object. However there is a potential problem here: All data that does not trigger binding failure is bound directly to the persistent object _before_ validation. If I understand the thread local session pattern correctly, any transactional method call that performs a flush after this point will cause Hibernate to collect all of the persistent objects that it knows about (all objects in the current session) and update the database with the contained values. <quote reference="hibernate_reference.pdf" chapter="8.4"> Persistent instances (ie. objects loaded, saved, created or queried by the Session) may be manipulated by the application and any changes to persistent state will be persisted when the Session is flushed (see "flushing" below). So the most straightforward way to update the state of an object is to load() it, and then manipulate it directly. </quote> and the relevant section on flushing: <quote reference="hibernate_reference.pdf" chapter="8.9"> >From time to time the Session will execute the SQL statements needed to synchronize the JDBC connection's state with the state of objects held in memory. This process, flush, occurs by default at the following points from some invocations of find() or iterate() from net.sf.hibernate.Transaction.commit() from Session.flush() </quote> Very sneaky, we don't even need to call update(persistent_object) to get our object persisted. At this point, Spring invokes a validator with the persistent object as its subject. If there are errors, the user will be forwarded back to the form. However, the database could be in an inconsistent state because any value that was successfully bound to the persistent object could possibly already have been persisted to the database due to some unrelated transactional method call. Please point out my error(s) here if I have made one or many. One potential solution (inspired by above mentioned post): Create a RequestWrapper that can be validated just like the persistent object to which the request will be bound (I realize this could be messy because it is essentially reverse reflection aka emulation). Then invoke the validator substituting the wrapped request for the actual object _before_ binding. Feedback is greatly appreciated. Thanks. Daniel Miller |