Mastering Spring BeanWrapper: Set, Get, and Convert Bean Properties Efficiently
This article introduces Spring's BeanWrapper, explains how to set and retrieve simple and nested properties, demonstrates indexed and key‑based access, covers automatic and custom type conversion using PropertyEditorSupport and Converter, and clarifies conversion priority and registration details for backend developers.
Environment: Spring 6.1.2
1. Introduction
BeanWrapper interface and BeanWrapperImpl implementation are important in Spring. They allow setting and getting property values (individually or in bulk), retrieving property descriptors, checking readability/writability, supporting nested properties, adding PropertyChangeListeners and VetoableChangeListeners without modifying target classes, and handling indexed properties. BeanWrapper is usually used by DataBinder and BeanFactory rather than directly by application code.
2. Practical Examples
2.1 Setting and Getting Basic and Nested Properties
Properties are accessed via setPropertyValue and getPropertyValue . Common expression forms include:
name – maps to getName()/setName(...)
account.name – nested property
account[2] – indexed property (array, List, etc.)
account[companyname] – Map key access
Example classes:
<code>public class Company {
private String name;
private Employee employee;
// getters and setters
}
public class Employee {
private String name;
private float salary;
private String[] address = new String[2];
private Map<String, String> account = new HashMap<>();
// getters and setters
}
</code>Manipulating these beans:
<code>BeanWrapper company = new BeanWrapperImpl(new Company());
// set simple property
company.setPropertyValue("name", "Pack Company Inc.");
// create employee and bind
Employee emp = new Employee();
BeanWrapper empWrapper = new BeanWrapperImpl(emp);
empWrapper.setPropertyValue("name", "张三");
empWrapper.setPropertyValue("salary", 66666.66f);
company.setPropertyValue("employee", empWrapper.getWrappedInstance());
// get nested property
Float salary = (Float) company.getPropertyValue("employee.salary");
System.out.println(salary);
System.out.println(company.getWrappedInstance());
</code>Output:
<code>66666.66
Company[name=Pack Company Inc., employee=Employee[name=张三, salary=66666.66]]
</code>2.2 Index Access
<code>Employee emp = new Employee();
BeanWrapper empWrapper = new BeanWrapperImpl(emp);
empWrapper.setPropertyValue("address[0]", "新疆");
empWrapper.setPropertyValue("address[1]", "重庆");
</code>2.3 Key Access
<code>BeanWrapper empWrapper = new BeanWrapperImpl(Employee.class);
empWrapper.setPropertyValue("account[home]", "H0001");
empWrapper.setPropertyValue("account[work]", "W0001");
System.out.println(empWrapper.getWrappedInstance());
</code>Output:
<code>Employee[name=null, salary=0.0, address=[null, null], account={work=W0001, home=H0001}]
</code>2.4 Automatic Type Conversion
When a string is assigned to a property of type float , BeanWrapper automatically converts it:
<code>BeanWrapper empWrapper = new BeanWrapperImpl(Employee.class);
empWrapper.setPropertyValue("salary", "88888.88");
</code>Spring loads all *Editor classes from org.springframework.beans.propertyeditors , e.g.,
<code>this.defaultEditors.put(Float.class, new CustomNumberEditor(Float.class, true));
</code>Default supported conversions are illustrated below:
2.5 Custom Type Conversion
Custom converters can be added via PropertyEditorSupport or Spring’s Converter interface.
Using PropertyEditorSupport :
<code>public class StringToUserEditor extends PropertyEditorSupport {
@Override
public void setAsText(String text) {
User user = new User();
String[] infos = text.split(",");
user.setAge(Integer.parseInt(infos[0]));
user.setName(infos[1]);
setValue(user);
}
}
</code>Register and use:
<code>BeanWrapper wrapper = new BeanWrapperImpl(Pack.class);
wrapper.registerCustomEditor(User.class, new StringToUserEditor());
wrapper.setPropertyValue("user", "23,张三");
System.out.println(wrapper.getWrappedInstance());
</code>Output:
<code>Pack[user=User[age=23, name=张三]]
</code>Using Spring’s Converter :
<code>public class StringToUserConvert implements Converter<String, User> {
@Override
public User convert(String source) {
User user = new User();
String[] infos = source.split(",");
user.setAge(Integer.parseInt(infos[0]));
user.setName(infos[1] + " -");
return user;
}
}
</code>Configure a ConversionService and apply:
<code>BeanWrapper wrapper = new BeanWrapperImpl(Pack.class);
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new StringToUserConvert());
wrapper.setConversionService(conversionService);
wrapper.setPropertyValue("user", "23,张三");
System.out.println(wrapper.getWrappedInstance());
</code>Output:
<code>Pack[user=User[age=23, name=张三 -]]
</code>2.6 Conversion Priority
If both a custom PropertyEditor and a Converter are registered, the PropertyEditor takes precedence, as shown by the following test:
<code>DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new StringToUserConvert());
wrapper.setConversionService(conversionService);
wrapper.registerCustomEditor(User.class, new StringToUserEditor());
// result: Pack[user=User[age=23, name=张三]]
</code>Spring determines the conversion order based on internal rules, illustrated below:
Note: If a matching XxxEditor exists in the same package as the target type, Spring can locate it automatically without explicit registration.
Testing without registering a converter still produces correct output, demonstrating the robustness of BeanWrapper’s conversion mechanism.
That concludes the article; hope it helps you work with Spring BeanWrapper more elegantly.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.