Classes with the @Controller or @ControllerAdvice annotations can have methods marked with the @InitBinder annotation that initialize WebDataBinder instances, and they, in turn, can:

  • Bind request parameters (that is, form or request data) to a model object.

  • Convert request string values (such as request parameters, path variables, headers, cookie data, etc.) to the target type of controller method arguments.

  • Format model object values as String values when displaying HTML forms.

Methods with the @InitBinder annotation can register controller-specific java.beans.PropertyEditor or Converter and Formatter components from Spring. Additionally, you can use MVC configuration to register the Converter and Formatter types in a globally shared FormattingConversionService.

Methods marked with the @InitBinder annotation support many of the same arguments as methods with the @RequestMapping annotation, with the exception of arguments annotated with @ModelAttribute (command object). Typically they are declared with a WebDataBinder argument (for registration procedures) and a void return value. The following listing is an example:

Java
@Controller
public class FormController {
    @InitBinder 
    public void initBinder(WebDataBinder binder) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        dateFormat.setLenient(false);
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
    }
    // ...
}
  1. Defining a method with the annotation @InitBinder.
Kotlin
@Controller
class FormController {
    @InitBinder 
    fun initBinder(binder: WebDataBinder) {
        val dateFormat = SimpleDateFormat("yyyy-MM-dd")
        dateFormat.isLenient = false
        binder.registerCustomEditor(Date::class.java, CustomDateEditor(dateFormat, false))
    }
    // ...
}
  1. Defining a method with the annotation @InitBinder.

Additionally, if you use Formatter based configuration via the generic FormattingConversionService, you can reuse the same approach and register controller-specific Formatter implementations, as shown in the following example:

Java
@Controller
public class FormController {
    @InitBinder 
    protected void initBinder(WebDataBinder binder) {
        binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
    }
    // ...
}
  1. Defining a method with the @InitBinder annotation for a custom formatter.
Kotlin
@Controller
class FormController {
    @InitBinder 
    protected fun initBinder(binder: WebDataBinder) {
        binder.addCustomFormatter(DateFormatter("yyyy-MM-dd"))
    }
    // ...
}
  1. Defining a method with the @InitBinder annotation for a custom formatter.

Model structure

In the context of web applications, data binding involves binding HTTP request parameters (that is, form data or request parameters) to properties of the model object and its nested objects.

For data binding, only public properties corresponding to JavaBeans naming conventions are exposed - for example, the public String getFirstName() and public void setFirstName(String) methods for the firstName property .

The model object and its nested object graph are also sometimes called the command object, base form object, or POJO("good old Java object").

By default, Spring allows binding to all public properties in the model object graph. This means that you need to think carefully about what public properties a model has, since a client can target any public property, even those not intended for a given use case.

For example, given an HTTP form data endpoint, a malicious client could pass values for properties that exist in the model's object graph but are not part of the HTML form presented in the browser. This may result in the model object and any of its sub-objects being set to data that is not expected to be updated.

The recommended approach is to use a specialized model object that exposes only those properties that are relevant to form submission. For example, in a form to change a user's email address, the model object must declare a minimal set of properties, as in the following ChangeEmailForm.

public class ChangeEmailForm {
    private String oldEmailAddress;
    private String newEmailAddress;
    public void setOldEmailAddress(String oldEmailAddress) {
        this.oldEmailAddress = oldEmailAddress;
    }
    public String getOldEmailAddress() {
        return this.oldEmailAddress;
    }
    public void setNewEmailAddress(String newEmailAddress) {
        this.newEmailAddress = newEmailAddress;
    }
    public String getNewEmailAddress() {
        return this.newEmailAddress;
    }
}

If you cannot or do not want to use a specialized model object for each use case of data binding, then you must restrict the properties that are allowed for data binding. Ideally, this can be done by registering allowed field patterns using the setAllowedFields() method in WebDataBinder.

For example, to register valid field patterns in your application, you can implement a method marked with the @InitBinder annotation in a component with the @Controller or @ControllerAdvice annotation as shown below:

@Controller
public class ChangeEmailController {
    @InitBinder
    void initBinder(WebDataBinder binder) {
        binder.setAllowedFields("oldEmailAddress", "newEmailAddress");
    }
    // methods annotated with @RequestMapping, etc.
}

In addition to registering valid field patterns, you can also register disallowed field patterns using the setDisallowedFields() method in DataBinder and its subclasses. However, note that the "allow list" is safer than the "deny list". Therefore, using setAllowedFields() should be preferred over using setDisallowedFields().

Note that pattern matching of valid fields is case sensitive; while matching against prohibited field patterns is not. Additionally, a field that matches a prohibited pattern will not be accepted, even if it also matches a pattern in the allowed list.

It is very important to correctly configure the valid and invalid field templates when directly opening the domain model for data binding. Otherwise it will be a big security risk.

Additionally, it is strongly recommended not to not use types from your domain model, such as JPA or Hibernate entities, as the model object in data binding scenarios.