Binding sits at the core of the Spring framework. In fact it is used in two different scenarios, as part of the inversion of control (IoC) container and in the MVC module. Beware that both use cases work in a completely independent way (although they share the same principles), that is the work for the former won't show up in the other unless it's replicated.
The IoC container needs binding capabilities to wire objects when injecting dependencies. This is one of the most basics features of Spring. For example, the following XML snippet declares a dependency that has to be wired on startup:
The IoC container needs binding capabilities to wire objects when injecting dependencies. This is one of the most basics features of Spring. For example, the following XML snippet declares a dependency that has to be wired on startup:
<bean id="oneBean" class="internna.OneClass">
<property name="runtimeClass" value="java.util.Date" />
</bean>
<property name="runtimeClass" value="java.util.Date" />
</bean>
How would Spring wire it at boot time? Well it really depends on the type, but assuming the field is declared as Class<?> runtimeClass, Spring would load the class and assign it to the variable using the correct setter (probably something like public void setRuntimeClass(Class<?> runtimeClass)).
The MVC framework twists a little the concept to be able to wire form fields to corresponding backing bean properties. In the end, everything is the same: there's a target object with a target property (of any type) that has to be filled based on the content of some string.
There's subtle magic happening there. First a String is converted to an actual object and second the binding happens. Let's try to explain it in detail.
The conversion mechanism is based on property editors. Everybody is used to work with them even if unconscious. Look at the following image of a property editor in action:

Of course, it's the typical use case. A GUI that needs to set the value of a property of something using just text (even though the actual variable may be anything..a Color or a Swing component in the example). Very common in IDEs indeed! The Spring team decided to mimic this approach even though there's no GUI really here. And such, they create PropertyEditors for the most common cases (classes, dates, files, urls...). The best of all is the extensibility of the solution (as with the rest of the framework). Custom editors can be easily developed and plugged. Let's see an example with something used in day by day development, JPA bindings.
The MVC framework twists a little the concept to be able to wire form fields to corresponding backing bean properties. In the end, everything is the same: there's a target object with a target property (of any type) that has to be filled based on the content of some string.
There's subtle magic happening there. First a String is converted to an actual object and second the binding happens. Let's try to explain it in detail.
The conversion mechanism is based on property editors. Everybody is used to work with them even if unconscious. Look at the following image of a property editor in action:

Of course, it's the typical use case. A GUI that needs to set the value of a property of something using just text (even though the actual variable may be anything..a Color or a Swing component in the example). Very common in IDEs indeed! The Spring team decided to mimic this approach even though there's no GUI really here. And such, they create PropertyEditors for the most common cases (classes, dates, files, urls...). The best of all is the extensibility of the solution (as with the rest of the framework). Custom editors can be easily developed and plugged. Let's see an example with something used in day by day development, JPA bindings.
public class JPAPropertyEditor extends PropertyEditorSupport {
public JpaEditor(Class<?> entityClass, PersistenceFacade persistenceManager) {
this.persistenceManager = persistenceManager;
this.entityClass = entityClass;
}
public void setAsText(String text) throws IllegalArgumentException {
Object entity = persistenceManager.find(entityClass, text);
setValue(entity);
}
}
public JpaEditor(Class<?> entityClass, PersistenceFacade persistenceManager) {
this.persistenceManager = persistenceManager;
this.entityClass = entityClass;
}
public void setAsText(String text) throws IllegalArgumentException {
Object entity = persistenceManager.find(entityClass, text);
setValue(entity);
}
}
As a matter of fact, the code above is surprisingly simple. It receives some text as the input (the primary key) and is capable of transforming it to a model object. The constructor may have as many parameters (of any type) as needed. This editor is then declared as any other bean in the context. As of now, Spring won't recognize the bean automatically and apply it to the bindings. It has to be registered before. This is done using a custom PropertyEditorRegistrar. This is not more than an interface with one method that has to be implemented
public class GenericRegistrar implements PropertyEditorRegistrar {
private Map<Class<?>, PropertyEditor> propertyEditors;
public void setPropertyEditors(Map<Class<?>, PropertyEditor> propertyEditors) {
this.propertyEditors = propertyEditors;
}
public void registerCustomEditors(PropertyEditorRegistry registry) {
if (getPropertyEditors() != null) {
for (Class<?> editorClass : getPropertyEditors().keySet()) {
PropertyEditor editor = getPropertyEditors().get(editorClass);
registry.registerCustomEditor(editorClass, editor);
}
}
}
}
private Map<Class<?>, PropertyEditor> propertyEditors;
public void setPropertyEditors(Map<Class<?>, PropertyEditor> propertyEditors) {
this.propertyEditors = propertyEditors;
}
public void registerCustomEditors(PropertyEditorRegistry registry) {
if (getPropertyEditors() != null) {
for (Class<?> editorClass : getPropertyEditors().keySet()) {
PropertyEditor editor = getPropertyEditors().get(editorClass);
registry.registerCustomEditor(editorClass, editor);
}
}
}
}
Finally, after declaring the registrar in the XML as well, just one step is left, informing Spring:
<util:list id="registrars">
<ref bean="genericRegistrar" />
</util:list>
<bean id="editorConfigurer" class="org.springframework...CustomEditorConfigurer">
<property name="propertyEditorRegistrars" ref="registrars" />
</bean>
<ref bean="genericRegistrar" />
</util:list>
<bean id="editorConfigurer" class="org.springframework...CustomEditorConfigurer">
<property name="propertyEditorRegistrars" ref="registrars" />
</bean>
Everything is done by now and JPA entities can be binded by the framework. Take into account, that the MVC data binders need to receive this registration independently.
The second trick Spring performs during data binding is setting the values. This is done by the BeanWrapperImpl, probably one of the most important classes in the framework. And the one you should be basing a data binder implementation upon. Things you should know about this class are:
The second trick Spring performs during data binding is setting the values. This is done by the BeanWrapperImpl, probably one of the most important classes in the framework. And the one you should be basing a data binder implementation upon. Things you should know about this class are:
- It wraps an instance of the bean to bind (so it cannot be a singleton)
- It can bind any type of property (depending on the configured editors)
- By default, all the Spring's editors are pre-configured
- Itcan be used to obtain property descriptors and values as well.
- MVC data binders use it internally
public class MyDataBinder extends GenericRegistrar {
protected BeanWrapper getWrapper(Object entity) {
BeanWrapper wrapper = new BeanWrapperImpl(entity);
registerCustomEditors(wrapper);
return wrapper;
}
public void bind(BeanWrapper beanWrapper, Map fields, Errors errors) {
for (String fieldName : fields.keySet()) {
try {
PropertyValue pv = new PropertyValue(fieldName, fieldValue);
beanWrapper.setPropertyValue(pv);
} catch (Exception ex) {
if (bindingErrors != null)
bindingErrors.rejectValue(fieldName, "error.binding");
}
}
}
}
protected BeanWrapper getWrapper(Object entity) {
BeanWrapper wrapper = new BeanWrapperImpl(entity);
registerCustomEditors(wrapper);
return wrapper;
}
public void bind(BeanWrapper beanWrapper, Map fields, Errors errors) {
for (String fieldName : fields.keySet()) {
try {
PropertyValue pv = new PropertyValue(fieldName, fieldValue);
beanWrapper.setPropertyValue(pv);
} catch (Exception ex) {
if (bindingErrors != null)
bindingErrors.rejectValue(fieldName, "error.binding");
}
}
}
}
Finally, just remember to check Chapter 5 of the Spring reference documentation when in doubt.
