Tuesday, 27 November 2018

Spring web mvc: property editors: customize properties binding

In this post, you are going to learn,
a.   What are property editors
b.   Property editors available in spring
c.   How to map text of type 'yyyy/mm/dd' to java.util.Date
d.   How to bind the Date of different format?

What are property editors?
Spring provides many property editors to customize the properties binding.

If you use @ModelAtribute annotation on method argument, spring binds all the request parameters to a java model object. But if you want any customizations in properties binding, you can achieve by using property editors.

For example, If the request parameter value is of format 'yyyy/mm/dd', then spring binds this value to java.util.Date. But if you want to bind parameter value of type 'yyyy@@mm@@dd' to kava.util.Date type, you should use property editors.

Property editors available in spring
Below table summarizes different property editors available in spring framework.

Property Editor
Description
Editor for byte arrays.
Editor for a Character, to populate a property of type Character or char from a String value.
Editor for char arrays.
Editor for java.nio.charset.Charset, translating charset String representations into Charset objects and back.
Property editor for an array of Classes, to enable the direct population of a Class[] property without having to use a String class name property as bridge.
Property editor for java.lang.Class, to enable the direct population of a Class property without recourse to having to use a String class name property as bridge.
Editor for java.util.Currency, translating currency codes into Currency objects.
Property editor for Boolean/boolean properties.
Property editor for Collections, converting any source Collection to a given target Collection type.
Property editor for java.util.Date, supporting a custom java.text.DateFormat.
Property editor for Maps, converting any source Map to a given target Map type.
Property editor for any Number subclass such as Short, Integer, Long, BigInteger, Float, Double, BigDecimal.
Editor for java.io.File, to directly populate a File property from a Spring resource location.
Editor for org.xml.sax.InputSource, converting from a Spring resource location String to a SAX InputSource object.
One-way PropertyEditor which can convert from a text String to a java.io.InputStream, interpreting the given String as a Spring resource location (e.g.
Editor for java.util.Locale, to directly populate a Locale property.
Editor for java.nio.file.Path, to directly populate a Path property instead of using a String property as bridge.
Editor for java.util.regex.Pattern, to directly populate a Pattern property.
Custom PropertyEditor for Properties objects.
One-way PropertyEditor which can convert from a text String to a java.io.Reader, interpreting the given String as a Spring resource location (e.g.
PropertyEditor implementation for standard JDK ResourceBundles.
Custom PropertyEditor for String arrays.
Property editor that trims Strings.
Editor for java.util.TimeZone, translating timezone IDs into TimeZone objects.
Editor for java.net.URI, to directly populate a URI property instead of using a String property as bridge.
Editor for java.net.URL, to directly populate a URL property instead of using a String property as bridge.
Editor for java.util.UUID, translating UUID String representations into UUID objects and back.
Editor for java.time.ZoneId, translating zone ID Strings into ZoneId objects.

How to map text of type 'yyyy/mm/dd' to java.util.Date?
I am going to develop a student registration form. Student must provide below information to register himself.

Information
Type
userName
String
age
int
hobbies
Collection
dateOfBirth
java.util.Date

public class Student {
         private String userName;
         private int age;
         private List<String> hobbies;
         private Date dateOfBirth;
         .....
         .....
}

There is nothing special about date mapping. Use the @ModelAttribute annotation on method argument of Student object, spring takes care of data binding for you.

@RequestMapping("/registerMe")
public ModelAndView getHelloMessage(@ModelAttribute("studentInfo") Student student, BindingResult bindingResult) {
         .....
         .....
}      

Find the below working application.

HelloWorldController.java

package com.sample.myApp.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.sample.myApp.model.Student;

@Controller
public class HelloWorldController {

 @RequestMapping("/registration")
 public String getRegistrationpage() {
  return "registration";
 }

 @RequestMapping("/registerMe")
 public ModelAndView getHelloMessage(@ModelAttribute("studentInfo") Student student, BindingResult bindingResult) {
  if (bindingResult.hasErrors()) {
   ModelAndView modelAndView = new ModelAndView("registration");
   return modelAndView;
  }

  ModelAndView modelAndView = new ModelAndView("welcome");

  modelAndView.addObject("message", "Dear User, your details are registered");

  return modelAndView;
 }

}

Student.java

package com.sample.myApp.model;

import java.util.Date;
import java.util.List;

public class Student {
 private String userName;
 private int age;
 private List<String> hobbies;
 private Date dateOfBirth;

 public Date getDateOfBirth() {
  return dateOfBirth;
 }

 public void setDateOfBirth(Date dateOfBirth) {
  this.dateOfBirth = dateOfBirth;
 }

 public String getUserName() {
  return userName;
 }

 public void setUserName(String userName) {
  this.userName = userName;
 }

 public int getAge() {
  return age;
 }

 public void setAge(int age) {
  this.age = age;
 }

 public List<String> getHobbies() {
  return hobbies;
 }

 public void setHobbies(List<String> hobbies) {
  this.hobbies = hobbies;
 }

}

Create registration.jsp, hello.jsp files under WEB-INF/jsp folder.


registration.jsp

<%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
<title>User Information Page</title>
</head>

<body>
 <h2 style="color:red;"><form:errors path="studentInfo.*" /></h2>

 <form method="post" action="/springdemo/registerMe" id="f1">
  <table>
   <tr>
    <td>User Name :</td>
    <td><input type="text" name="userName" value="" /></td>
   </tr>
   <tr>
    <td>Age :</td>
    <td><input type="text" name="age" value="" /></td>
   </tr>
   <tr>
    <td>Hobbies :</td>
    <td><select multiple name="hobbies">
      <option value="cricket">Cricket</option>
      <option value="chess">Chess</option>
      <option value="football">Football</option>
      <option value="tennis">Tennis</option>
    </select></td>
   </tr>
   
   <tr>
    <td>Date Of Birth</td>
    <td><input type="text" name="dateOfBirth" value="" /></td>
   </tr>
   <tr>
    <td><input type="submit" name="submit" value="submit"
     style="font-size: 18px;" /></td>
   </tr>
  </table>
 </form>

</body>
</html>

welcome.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
 pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Hello World Spring Web MVC</title>
</head>
<body>
 <h1>${message}</h1>

 <h3>
  User Name : ${studentInfo.userName} <br /> 
  Age : ${studentInfo.age} <br />
  Hobbies: ${studentInfo.hobbies} <br />
  Date Of Birth: ${studentInfo.dateOfBirth}
 </h3>
</body>
</html>

Create web.xml, HelloWorld-servlet.xml files under WEB-INF folder.


web.xml

<web-app id="WebApp_ID" version="2.4"
 xmlns="http://java.sun.com/xml/ns/j2ee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

 <display-name>Spring MVC Hello WorldApplication</display-name>

 <servlet>
  <servlet-name>HelloWorld</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>

 <servlet-mapping>
  <servlet-name>HelloWorld</servlet-name>
  <url-pattern>/</url-pattern>
 </servlet-mapping>

</web-app>

HelloWorld-servlet.xml

<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="
   http://www.springframework.org/schema/beans     
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/context 
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">

 <context:component-scan
  base-package="com.sample.myApp" />

 <bean
  class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="prefix" value="/WEB-INF/jsp/" />
  <property name="suffix" value=".jsp" />
 </bean>

</beans>

Create index.jsp file under webapp folder.


index.jsp

<%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
<title>Welcome Page</title>
</head>

<body>
 <h3>Dear Student, click on below button to register yourself</h3>
 <form method="post" action="/springdemo/registration" id="f1">
  <input type="submit" name="submit" value="submit"
   style="font-size: 18px;" />
 </form>
</body>
</html>

Project structure looks like below.


Run the application on server. You can able to get below kind of screen.



Click on submit button, it navigates you to the registration page.



Fill the registration form, fill the date in ‘YYYY/MM/DD’ format. Click on submit button.


You can able to see successful message like below.



Now go back to the registration page again and enter the date in ‘YYYY@@MM@@DD’ format.


Click on submit button, you can able to see below kind of data bind error.



It is because, spring doesn’t know how to bind the string of format ‘YYYY@@MM@@DD’ to date type.

How to bind the Date of different format?
By using custom property editors, we can customize the data binding process.

For example, below method customize the date format. I am using spring CustomDateEditor class to support custom date format.

@InitBinder
public void customizeBinding(WebDataBinder dataBinder) {
         SimpleDateFormat dateFormat = new SimpleDateFormat("YYYY@@MM@@DD");
         dataBinder.registerCustomEditor(Date.class, "dateOfBirth", new CustomDateEditor(dateFormat, false));
}

Update HelloWorldController class like below.

HelloWorldController.java

package com.sample.myApp.controllers;

import java.sql.Date;
import java.text.SimpleDateFormat;

import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.sample.myApp.model.Student;

@Controller
public class HelloWorldController {

 @InitBinder
 public void customizeBinding(WebDataBinder dataBinder) {
  SimpleDateFormat dateFormat = new SimpleDateFormat("YYYY@@MM@@DD");
  dataBinder.registerCustomEditor(Date.class, "dateOfBirth", new CustomDateEditor(dateFormat, false));
 }

 @RequestMapping("/registration")
 public String getRegistrationpage() {
  return "registration";
 }

 @RequestMapping("/registerMe")
 public ModelAndView getHelloMessage(@ModelAttribute("studentInfo") Student student, BindingResult bindingResult) {
  if (bindingResult.hasErrors()) {
   ModelAndView modelAndView = new ModelAndView("registration");
   return modelAndView;
  }

  ModelAndView modelAndView = new ModelAndView("welcome");

  modelAndView.addObject("message", "Dear User, your details are registered");

  return modelAndView;
 }

}

Re deploy the application on server. Now enter the date in ‘YYYY@@MM@@DD’ format.


Click on submit button. You can able to see successful message.


In my next post, I am going to explain about property editors.


Previous                                                 Next                                                 Home

No comments:

Post a Comment