Close

Spring MVC - Customizing existing formatters using @InitBinder

[Last Updated: Jun 7, 2018]

Starting Spring 3 a new formatter approach can be used as an alternative to PropertyEditors.

Spring 3 introduces a convenient Formatter SPI that provides a simple and robust alternative to PropertyEditors for client environments.
In general, use the Converter SPI when you need to implement general-purpose type conversion logic; for example, for converting between a java.util.Date and and java.lang.Long. Use the Formatter SPI when you're working in a client environment, such as a web application, and need to parse and print localized field values. The ConversionService provides a unified type conversion API for both SPIs.

Formatters specify the data format to be rendered in user interface. They also provide a way to convert string input from user interface to Java data type.

Converter are used to convert one type to another.

In this example we are going to hook up Spring built-in Formatters: DateFormatter, NumberStyleFormatter and CurrencyStyleFormatter.

We will use @InitBinder approach.



Creating the Controller

This controller handles trade requests based on trade id : /trades/23

@Controller
@RequestMapping("trades")
public class TradeController {

    @Autowired
    private TradeService tradeService;

    @InitBinder
    private void customizeBinding (@PathVariable("tradeId") long tradeId,
                                   WebDataBinder binder) {
        Trade trade = tradeService.getTradeById(tradeId);
        if (trade == null) {
            return;
        }

        DateFormatter dateFormatter = new DateFormatter();
        dateFormatter.setPattern("MM-dd-yyyy");
        binder.addCustomFormatter(dateFormatter, "tradeDate");

        NumberStyleFormatter numberFormatter = new NumberStyleFormatter();
        numberFormatter.setPattern("#,###,###,###.##");
        binder.addCustomFormatter(numberFormatter, "amount");


        CurrencyStyleFormatter currencyFormatter = new CurrencyStyleFormatter();
        currencyFormatter.setCurrency("Buy".equals(trade.getBuySell()) ?
                                      trade.getBuyCurrency() : trade.getSellCurrency());
        binder.addCustomFormatter(currencyFormatter, "amount");
    }

    @RequestMapping("/{tradeId:\\d+}")
    public String handleTradeRequest (@PathVariable("tradeId") long tradeId, Model model) {
      ........
    }
}



Backing Object

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Currency;

public class Trade {

    private long tradeId;
    private String buySell;
    private Currency buyCurrency;
    private Currency sellCurrency;
    private BigDecimal amount;
    private LocalDate tradeDate;

   // getters and setters

}



The JSP page

We have to use spring bind tag for formatting to work.

<%@ page language="java"
    contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@taglib uri="http://www.springframework.org/tags" prefix="spring" %>
<html>
<body>
   <h3> Showing Trade with Id ${trade.tradeId} <h3>
   <p>BuySell: ${trade.buySell}</p>
   <p>Buy Currency: ${trade.buyCurrency}</p>
   <p>Sell Currency: ${trade.sellCurrency}</p>
   <p>Amount :
   <spring:bind path="trade.amount">${status.value}</spring:bind>
   </p>
   <p>Trade Date :
      <spring:bind path="trade.tradeDate">${status.value}</spring:bind>
      </p>
</body>
</html>


With customized formatting:



Without formatting:



Registering Formatter Globally

In above example we used @InitBinder to customize formatters. Alternatively we can register our custom formatter globally in @Configuration class:

@EnableWebMvc
@Configuration
public class TradeConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addFormatters (FormatterRegistry registry) {
    //add formatter and converter here
        registry.addFormatter(....);
    }
}

We used similar configuration in our custom Converter Example.

Global registration of a Formatter should be used if it's on field data type rather than on field name.

In @InitBinding approach, we configure formatter and property editors on per request basis and we have an option to specify field names. Also we can access more dynamic information on @InitBinding level. For example in our above example we are getting the Trade instance based on path variable tradeId. We are doing so to decide on the CurrencyStyleFormatter currency option.



Example Project

To test controllers run the unit tests in RegistrationControllerTest.

Or you can run the app using embedded tomcat:

mvn  clean install tomcat7:run-war

Dependencies and Technologies Used:

  • Spring Web MVC 4.2.4.RELEASE: Spring Web MVC.
  • Spring TestContext Framework 4.2.4.RELEASE: Spring TestContext Framework.
  • Java Servlet API 3.0.1
  • JUnit 4.12: JUnit is a unit testing framework for Java, created by Erich Gamma and Kent Beck.
  • JDK 1.8
  • Maven 3.0.4

Spring Custom Formatter Example Select All Download
  • spring-formatters
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • TradeController.java
          • webapp
            • WEB-INF
              • views
        • test
          • java
            • com
              • logicbig
                • example

    See Also