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


Beware of removing Deprecated Method

May 4, 2009

One of the common task on reviewing code is removing deprecated method. Sometimes it sounds dangerous and make some bug too. Last week I have found an interesting miss flow of a widely used deprecated method. RequestUtils.getStringParameter(request, “stringParameter”, defaultValue) method used to get a string parameter from the request. Suppose you are retrieving value of this string parameter from the request in a way that if there is no value, the it will pass a default value.


String doIt = RequestUtils.getStringParameter(request, "doIt", null);

If the request contains variable doIt then it returns value of doIt. Otherwise it suppose to give null. My task was simple. I replaced the deprecated class with ServletRequestUtils like the following and having some trouble.


String doIt = ServletRequestUtils.getStringParameter(request, "doIt", null);

Later I discovered a strange thing. In view layer doIt was kept as a hidden variable with a default value of empty string “”. Deprecated RequestUtils class return null in place of empty string and that buggy code works really fine in Firefox browser. After I replace the deprecated one, the actual flow crushed cause it took decision by comparing null value not by empty string.

by: Md. Shahjalal


Spring JdbcTemplate to retrieve List and Map

February 15, 2009

org.springframework.jdbc.core.JdbcTemplate used to perform query for specific result through out some query parameters. Some of the basic queries like query, queryForList, QueryForObject as the common understandings of the methods name. A query or queryForList method returns a list of desired rows but queryForMap returns only a single row where all the column names are key of the Map.

To retrieve a list, org.springframework.jdbc.core.RowMapper can be used along with java.sql.ResultSet. A sample code is like,


List sampleClassList = jdbcTemplate.query(query, new Object[]{parameters.....},
new RowMapper() {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
SampleClass sampleClass = new SampleClass();
sampleClass.setValue1(rs.getString("column1"));
sampleClass.setValue2(rs.getString("column2"));
return sampleClass;
}
});

In most of the cases developers convert a retrieved list to their desired Map later by manipulating the list. The basic reason behind is a map will not contain duplicate values as key but to a list data can be redundant. Its also possible to get a Map where one column as key and other as value of the map. org.springframework.jdbc.core.ResultSetExtractor can be used for customize results like Map. The following sample code can do this thing. Its really a very good option if one do not want to have duplicate value in a specific column. Its easier to make that thing a key.


Map map = (Map)jdbcTemplate.query(query, new Object[]{parameters....},
new ResultSetExtractor() {
public Object extractData(ResultSet rs) throws SQLException {
Map map = new LinkedHashMap();
while (rs.next()) {
String col1 = rs.getString("col1");
String col2 = rs.getString("col2");
map.put(col1, col2);
}
return map;
};
});

By: Md. Shahjalal


JMS with Spring Framework

January 18, 2009

Uses of Java Messaging Service (JMS) are populated across the web applications. Spring framework provides JMS integration framework to simplify the use of this useful message publisher (message production) and consumer (synchronous/asynchronous message reception) technology. Class JMSException (org.springframework.jms.support) can be used for exception handling. MessageConverter (org.springframework.jms.support.converter) can be used abstract for the conversion between Java Object and JMS Message. The org.springframework.jms.support.destination package is useful for managing various strategy message destination such as router settings. JmsAccessor (org.springframework.jms.support) class used for connection factory and session acknowledgment mode. For handling connection management spring provides package org.springframework.jms.connection

JmsTemplate class is used for sending a message while MessageCreator is used for creating a message. Both of these classes are part of org.springframework.jms.core package of Spring framework. A simple message can be created by using Message (javax.jms.Message) class for publishing. Following code can be used to create a sample message by a publisher class:


import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;

import javax.jms.Message;
import javax.jms.Session;
import javax.jms.JMSException;
import javax.jms.ObjectMessage;

public class simpleJmsPublisher {
private JmsTemplate jmsTemplate;
public void publish(final MessageClass messageToPublish) {
jmsTemplate.send(new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
ObjectMessage message = session.createObjectMessage();
message.setObject((Serializable)messageToPublish);
return message;
}
});
}
}

Implementation of onMessage() method of MessageListener (javax.jms.MessageListener) interface in the consumer class used to receive the message that was published from publisher class.


import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

public class simpleJmsConsumer implements MessageListener {
public void onMessage(Message receivedMessage) {
if (receivedMessage instanceof MessageClass) {
try {
//Do the specific task to be done by receiving message
} catch (JMSException ex) {
throw new RuntimeException(ex);
}
} else {
throw new IllegalArgumentException(“Message must be of type MessageClass”);
}
}
}

Source : http://static.springframework.org/spring/docs/2.5.x/reference/jms.html

by: Md. Shahjalal


Follow

Get every new post delivered to your Inbox.