Previously, I wrote an article on how to achieve dynamic list binding in Spring MVC. Since I wrote that article, I have received emails and comments that ask (in a roundabout way) Why would I need to do this? When I wrote the other article I didn't explain the why; I just wrote the how. Here's why you need dynamic binding and the problems it is trying to solve.
Example
Let's say that you have an application that allows you to modify a Hand. As in the thing at the end of your arm. You have a two class object model: Hand and Finger. A Hand has Fingers. More specifically, a Hand has a List of Fingers. For the impatient (who don't want to read the Why section), I created an online application to demonstrate some of the issues.
Why
Here are some reasons why you need dynamic binding in general:
- Creating the object graph takes a really long time
- The object graph could have changed between subsequent page calls
- The page allows for list changes via javascript
Creating the object graph takes a really long time
Let's say that creating a Hand from its persistent storage takes a really long time. You will want to minimize the number of times you go to that persistent storage. Spring invokes the formBackingObject() method in controllers to create object graphs that will be used with web forms.
Let's say that creating a Hand from its persistent storage takes a really long time. You will want to minimize the number of times you go to that persistent storage. Spring invokes the formBackingObject() method in controllers to create object graphs that will be used with web forms.
In our example, when the Edit Hand page is being loaded, the formBackingObject() method is invoked and the page (with the form) is displayed. When that page is submitted, Spring will invoke the formBackingObject() method and then overlay the results of the form onto the object graph returned from that method invocation. So what just happened? You just invoked an expensive method twice.. once for display, once for submission. The second invocation was completely unnecessary. In order to stop the second invocation, you will have something like this in your formBackingObject() implementation:
if (!isFormSubmission(request)) {
//create expensive object graph
} else {
//create non-populated object graph shell
}So what's the problem? Nothing with regard to the initial page load (provided it isn't from a form submit), but the submission will fail with an Exception. In our example, the List of Fingers on the Hand will be empty when the submission takes place. Spring will then try to get the first Finger out of the List (in order to overlay the values) but will fail because the List is empty.
The object graph could have changed between subsequent page calls
Now let's say that it isn't all that expensive to create a Hand from persistent storage. The double call to formBackingObject() isn't really that big of a deal from a cost (cpu, elapsed time, etc) perspective. Let's say you are on the Edit Hand page typing in your edits. Another user goes to the Edit Hand page, removes a Finger and submits the changes. Now you finish your edits and hit submit. That submit will fail. The reason is the List of Fingers. In the first call, you get a Hand with a List containing five Fingers and those five Fingers are rendered on the page. In the second call, you get a Hand with four Fingers that Spring attempts to overlay the four finger graph with the elements on the form (which has five fingers). The fifth finger will error out.
Now let's say that it isn't all that expensive to create a Hand from persistent storage. The double call to formBackingObject() isn't really that big of a deal from a cost (cpu, elapsed time, etc) perspective. Let's say you are on the Edit Hand page typing in your edits. Another user goes to the Edit Hand page, removes a Finger and submits the changes. Now you finish your edits and hit submit. That submit will fail. The reason is the List of Fingers. In the first call, you get a Hand with a List containing five Fingers and those five Fingers are rendered on the page. In the second call, you get a Hand with four Fingers that Spring attempts to overlay the four finger graph with the elements on the form (which has five fingers). The fifth finger will error out.
The page allows for list changes via javascript
On the first call, a Hand with five Fingers is returned and displayed. However, this is one of those fancy web 2.0 kind of pages... one where you can click an Add New Finger button and magically the new Finger appears without submitting the form. Once you finish adding Fingers you eventually click the submit button.. only to fail miserably. Much like the previous two reasons, the mismatch between the number of Fingers on the form and the number of Fingers in persistent storage is the problem. When Spring attempts to overlay the new set of Fingers from the form onto the graph created by formBackingObject() there is a mismatch.. the new form has let's say 12 Fingers.. while the graph from storage still only has five Fingers. When the overlaying of the sixth finger is attempted an Exception is thrown.
On the first call, a Hand with five Fingers is returned and displayed. However, this is one of those fancy web 2.0 kind of pages... one where you can click an Add New Finger button and magically the new Finger appears without submitting the form. Once you finish adding Fingers you eventually click the submit button.. only to fail miserably. Much like the previous two reasons, the mismatch between the number of Fingers on the form and the number of Fingers in persistent storage is the problem. When Spring attempts to overlay the new set of Fingers from the form onto the graph created by formBackingObject() there is a mismatch.. the new form has let's say 12 Fingers.. while the graph from storage still only has five Fingers. When the overlaying of the sixth finger is attempted an Exception is thrown.
Solution
In addition to an explanation of the how, I created an online web application to illustrate the problem and the solution. The source war is also attached to this article below.
Filename/TitleSizeDynamicFormsExample.war (http://mattfleming.com/files/active/0/DynamicFormsExample.war)3.09 MB
Aucun commentaire:
Enregistrer un commentaire