Allow fields of list of Beans in SimpleFormController of Spring MVC

June 10, 2009

ServletRequestDataBinder of Spring framework is used  to protect unwanted biding of attributes of Bean in SimpleFormController of Spring MVC. You can define precisely which fields will be bind to the bean in view layer. Programmer used to do it by overriding the createBinder() method. Explicitly define the allowed fields in a String array and set in (servletRequestDataBinder.)setAllowedFields(allowedFields) method. Now think of a bean where you have a list of another bean. For example a bean of Course contains multiple sections.

class Bean {
.....
int id
String courseName;
List sections;
.....
}
class Section {
int id
String facultyName;
}

You have override the createBinder() method and code as follows

protected ServletRequestDataBinder createBinder(HttpServletRequest request, Object o) throws Exception {
ServletRequestDataBinder servletRequestDataBinder = super.createBinder(request, o);
String[] allowedFields = {"courseName"};
return servletRequestDataBinder.setAllowedFields(allowedFields);
}

Now how to allow your preferred fields of section with it? Well the solution is really simple. Bean elements of a list are represent by a special format in spring. And the format is:

listName[listIndex].fieldName

So you can make your required binder by following code:

protected ServletRequestDataBinder createBinder(HttpServletRequest request, Object o) throws Exception {
ServletRequestDataBinder servletRequestDataBinder = super.createBinder(request, o);
String[] allowedFields = {"courseName", "sections[0].facultyName"};//for 1 section
return servletRequestDataBinder.setAllowedFields(allowedFields);
}

You can run a loop for number of sections and make a list and eventually covert the list into an array list for allowing preferred fields.

By: Md. Shahjalal


Multiple session or multi-window problem and solution where same form opened in multiple tab or window extended from SimpleFormController of Spring MVC

June 4, 2009

My previous entry about multi-window or Multiple session shows how we can maintain different session for a same form extended from SimpleFormController of Spring MVC, used by multiple class. Now what about a Form extended from SimpleFormController of Spring MVC opened in different tab or window? A new one will always replace the bean from the session after showing form on showForm() method.

showForm() method of SimpleFormController save the bean in session if setSessionForm(true) for that form just before redering the view. Session works like a HashMap. It saves the bean by a name and this name retrived by calling getFormSessionAttributeName() method. Which is simply the class name(with prefix of package name) + “.Form.command”. So the new bean always replaces the old one in session.

Problem: For example you have a Patient data entry form extended from SimpleFormController of Spring MVC. You want to update two patiend information in two different tab of your browser. You open one form fill up all data and before submit you open another form in another tab. Now the bean in the session will be replaces by this new patient’s information. Now you submit this and get back to previous tab and submit that. onSubmit() method retrive the bean from the session which is the information of the second tab. So you will get incompatible data.

Solution: Soluation is same as the previous entry. You have to override  getFormSessionAttributeName(HttpServletRequest request) method and make sure two name in the session is different. Find a unique identity for two different form. It can be patient id assigned by Hospital or clinic or database index of the patient in storage device. Choosing database index has a problem. Before you submit a new form, you do not know the index so this key is 0(=zero) for a new form.

You can generate a patient id for a new form and keep it as a request attribute and modify session attribute name by overriding getFormSessionAttributeName(HttpServletRequest request) like following code

//to set inrequest:
request.setAttribute("patientId", patientId);
//in getFormSessionAttributeName(HttpServletRequest request) method
@Override
protected String getFormSessionAttributeName(HttpServletRequest request) {
String patientId = (String)request.getAttribute("patientId");
return super.getFormSessionAttributeName()+"."+patientId;
}

So when controller calls getFormSessionAttributeName() it got different session attribute name for two different name and overwrite of bean is prohibited.

by Md. Shahjalal


Choosing a Controller for your work in Spring MVC

July 24, 2008

Spring provides good number of well structured Controller to work with Spring MVC and work flow. If you are familiar with Spring frame work, you must have work with two master piece controller SimpleFormControllerand and AbstractController. One for only view read-only request and other one includes full form handling mechanism. But this are not the end of the world. There are several Controllers that one can choose for various purpose.

AbstractWizardFormController Think about a form thats large in length. User have to scroll down dipper to fill up all the necessary fields of a form. Suppose, you are filling a long form to be a member of a job site, where there are sections like Name and Address, Job experience, Educational back grounds, Achievements e.t.c. But if all those thing bind with a single been then how about Splits this form across multiple pages? If you really want to do some thing like this, this is the controller for you :D

MultiActionController You are working with Spring MVC not in Web-Flow. But some time it needs to handle more work flow than a single one. Well though its possible to do the same task with AbstractFormController but the number of Controller will be more. For handling multiple action, this controller provides three different method:
public ModelAndView doStuff(HttpServletRequest req,
HttpServletResponse res) { … }
public ModelAndView doOtherStuff(HttpServletRequest req,
HttpServletResponse res, HttpSession session) { … }
public ModelAndView doStuff(HttpServletRequest req,
HttpServletResponse res, CommandBean command) { … }

One can choose any one of those on his requirement. But the basic problem with this Controller is it does not provide any work flow. All of this must be done by manually.

ThrowawayController The flavour of Command Pattern comes with this controller in Spring MVC. If you do not like to work with request/response stateless controller. The controller itself work as a command bean. Non-singleton. Lack of validation enforce another version of the controller named ValidatableThrowawayController.

By: Md. Shahjalal


Workflow of SimpleFormController of Spring MVC

February 27, 2008

The entire life cycle of a HTML form is handled by SimpleFormController of Spring MVC. The tasks of form viewing, validation, submission are maintained in complex but magical way by this Class. The parent class (AbstractFomController) stopped its functionality up to form viewing where as this class run to the end for doing extra works of form submission. There are a lot of method works across the class to perform a solid support to the system but few of those play key roles and a developer should know to work with it. Following section will cover these things:

isFormSubmission(): Checkout is the HTTP request is for form viewing or submitting. For post method it returns true. In fact, this method leads to one of two main stream of form view and form submit. This act as the divider for two flow.

formBackingObject(): Creates instance of the form object. By default it follows the the class set by method setCommandClass(). You can configure it in your servlet.xml’s bean property by
<property name=”commandClass”>
<value>project.db.beanClass</value>
</property>
This is not final so that you can add extra things with it. For example, for saving a form in DB we maintain a id as primary key which starts from 1. Then you can add a checking of id>0 or not find out its a new form or old form.

initBinder(): This method called after the instance of the form is created and the controller creates the data binder. Programmer used to override this method to register custom PropertyEditors for a form. Suppose, to bind date, time related things with the form object. If there is no binding like these, this method do nothing(By default).

setBindOnNewForm(): While you have the dataBinder instance is ready, you are allowed to perform biding parameters comes with initial HTTP GET request. The action is fixed by the bindOnNewForm property set by this method.

isSessionForm(): Determines the form is in the session or not. If so, it store the form in the session. By setting setSessionForm() = true one can let the controller to enable this feature. Many ORM tool supports reattaching, or merging, a detached bean. So setSessionForm() to true gives lot advantages to developers. But mind it, it takes a lot of memory too. At the form submission cycle(by HTTP POST request) if the method returns true, the form will be retrieved from session and remove it from session for farther work. But in case of any error in form submission process, the form will be placed back into session.

isValidateOnBinding(): If true then run all the validations of the form. This is too important for the controller so by default set to true and marked final. Only way to change it is through setValidateOnBinding() method.

suppressValidate(): If coder needs more controlled validation over the form after binding variables are welcome to use this method. It allows to choose on a request-by-request basis whether or not to run through the validations.. By default it is false. It may be confusing that why should you use a request-by-request validation for the form though you have method like onBindAndValidate() activated later. Think of a scenario where you validate all for update, insert, delete e.t.c for form submission. A delete operation do not need to perform non empty fields, can directly delete from DB. So, one can handle delete by suppressValidation.

referenceData(): At the end of process of form viewing it collect reference data by this method. For example, once need to show all the state list of a country in a drop down list. In this method one can provide the list in a map for displaying in the form. These are called auxiliary object for the form. After this the Controller assemble the full model with the form object, any possible errors from potential binding, and the model from referenceData(). It will then send this combined model to the View fixed by formView property of the bean in servlet.xml file. The from will lead to a successful view.

onBindAndValidate(): The callback method allows to perform any custom validation logic or general logic after binding and validation. After this method the controller look for any error occurs or not. If error then the form will be stored in the session (where setSessionForm() == ture) and show the original form otherwise successfully complete form submission method.

By: Md. Shahjalal

References:
1. Expert Spring MVC and Web Flow
2. wikipedia


Follow

Get every new post delivered to your Inbox.