Register | Forgot password
All Blogs...
Originally, I planned to post all the 5 answers at the same time. But while writing the answer to the first issue, I figured this would become a very long post. And so I'll discuss only one issue at a time, starting with Fuzzy issue 1. Let's first recap the issue;
Fuzzy issue 1Take a look at the following code snippet in the Form Backing Object of your panel. The Form Backing Object implements a toString(), just for logging purposes. That cannot possibly be wrong, can it?
public class MyFBO implements FormBackingObject {
...
public String toString() {
String bla = "";
for (int i=0; i<5000; i++) {
bla += "bla";
}
return bla;
}
}
Question: what will happen here?
A. This large String somehow suddenly appears in the generated HTML of the panel.
B. An Exception is displayed in the Tomcat console and the
panel doesn't open at all.
C. Initially the panel seems to works fine but after submitting once you get a blank page. No errors visible in Tomcat. The panel seems to have died.
The answer
Well, the answer to this question is B. Your panel will be broken and this error appears in the Tomcat console:
java.lang.ArrayIndexOutOfBoundsException
at java.lang.System.arraycopy(Native Method)
at org.apache.coyote.http11.InternalOutputBuffer.write(InternalOutputBuffer.java:689)
...
The POST and REDIRECT pattern
The POST and REDIRECT pattern is about separation of handling updates versus building the view. When you open a panel, there are no updates to perform. The only thing that needs to be done is building the view; the HTML that makes up the panel. To open the panel a GET request is send to the Spring controller and the querystring of the URL contains information about the panel to open.
But when the user for example presses the 'create entity' button in the panel, we actually have to perform some updates to the underlying datamodel. We will have to perform the update based on what the user entered in the HTML form that was submitted. The form for example may contain the name of the new entity to be created. In this case a POST request is send containing all entered form values by the user.
However, besides handling this update action also the view of the panel has to be build up again, probably showing the newly created entity. The POST and REDIRECT pattern is about separation of these two concerns. The separation is done this way:
POST
If a POST request is send to a Spring controller, Spring will bind the values entered in the form to your Form Backing Object. So it will invoke the bind methods like onBind() and onBindAndValidate(). Finally, it invokes onSubmit(). In the onSubmit() you are supposed to handle the datamodel updates. The result of the onSubmit() method is a ModelAndView. And there is the trick; the view returned by the onSubmit() method is actually a redirect (302). The redirect now points to a URL that is very similar to the URL to open the panel and results in a GET request. The only difference is that it may contain some additional parameters in the query string.
GET
If a GET request is send to a Spring controller, Spring will NOT bind the values entered in the form to your Form Backing Object. It doesn't need to, there are no posted form values to handle. Instead it will directly invoke showForm() which in his turn invokes referenceData(). The showForm() returns the final view that builds up the panel.
Back to the issue
Now that we understand the POST and REDIRECT pattern, we can explain what happens here. The problem is caused when Spring builds up the redirect view. Note that the onSubmit() returns a ModelAndView object. The view will be a RedirectView, the model may contain all kind of information. You can put whatever you want onto the model. One of the stuff that is put on the model by default is the Form Backing Object. Spring figures that any values put on the model might also be relevant when building up the view after the redirect. So if you put a 'pageid' onto the model in the onSubmit(), you may need this value later on in the showForm(). The only way to do this is by appending the model values to the query string (the redirect will result in a GET request). So Spring loops over all values put on the model, performs a toString() and appends '&key=value.toString()' to the query string of the redirect URL. This is what causes the issue; it tries to pass the Form Backing Object by appending "&command=" + fbo.toString() to the query string of the redirect URL. When the toString() of the FBO is too large, the length of the URL exceeds the limits of the browser, your webserver or Tomcat causing the exception and the broken panel.
ConclusionYou might think the example is a little bit 'seeking for problems' but it really isn't. The problem comes from the field in a case that the toString() was used to generate an XML representation of something 'quite large'. In fact, the issue is always there but as long as you don't exceed the URL limit you probably won't even notice it. But now that you know this issue exists, take a good look at the URL in the address bar of your browser and see what happens after submitting your own custom panel. Notice that this 'weird' parameter is appended:
%40f9caf2&org.springframework.validation.BindingResult.command=org.springframework.validation.BeanPropertyBindingResult%3A+0+errors
Return to all blogs
Ivo Ladage is product architect and is part of one of the SCRUM-teams. Ivo has special interests in Workflow and Authorization processes and Spring MVC.
Read all Ivo's blog entries
Other blog entries: