代码位置:
spring-beans:org.springframework.beans.BeanWrapper
查看其继承关系,可以发现其有三个主要的父接口和一个实现类,如下所示:
所以只要了解了这三个接口的能力,那么BeanWrapper的作用就差不多了。
PropertyAccessor
主要的作用:读写Bean的属性;
源码
public interface PropertyAccessor {
String NESTED_PROPERTY_SEPARATOR = ".";
char NESTED_PROPERTY_SEPARATOR_CHAR = '.';
String PROPERTY_KEY_PREFIX = "[";
char PROPERTY_KEY_PREFIX_CHAR = '[';
String PROPERTY_KEY_SUFFIX = "]";
char PROPERTY_KEY_SUFFIX_CHAR = ']';
// 判断属性是否可读,其实就是判断是否有get方法
boolean isReadableProperty(String propertyName);
// 判断属性是否可写,其实就是判断是否有set方法
boolean isWritableProperty(String propertyName);
// 获取属性类型
@Nullable
Class<?> getPropertyType(String propertyName) throws BeansException;
// 获取TypeDescriptor,属性描述器
@Nullable
TypeDescriptor getPropertyTypeDescriptor(String propertyName) throws BeansException;
// 获取属性的值
@Nullable
Object getPropertyValue(String propertyName) throws BeansException;
// 设置属性的值
void setPropertyValue(String propertyName, @Nullable Object value) throws BeansException;
// 设置属性的值
void setPropertyValue(PropertyValue pv) throws BeansException;
// 批量设置属性的值
void setPropertyValues(Map<?, ?> map) throws BeansException;
// 批量设置属性的值
void setPropertyValues(PropertyValues pvs) throws BeansException;
// 批量设置属性的值
void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown)
throws BeansException;
// 批量设置属性的值
void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)
throws BeansException;
}
拿 BeanWrapper测试下
@DisplayName("测试对Bean属性的读写能力")
public class PropertyAccessorTest {
@Test
public void beanWrapperTest() {
Car car = new Car();
car.setName("笨笨");
car.setWeight(1000D);
car.setLabels(Lists.list("a,b,c"));
car.setProps(Maps.newHashMap("color", "red"));
BeanWrapper beanWrapper = new BeanWrapperImpl(car);
Class<?> type = beanWrapper.getPropertyType("type");
System.out.println("获取属性type:" + type);
boolean readName = beanWrapper.isReadableProperty("name");
System.out.println("属性name是否可读:" + readName);
boolean writeWeight = beanWrapper.isWritableProperty("weight");
System.out.println("属性weight是否可写:" + writeWeight);
TypeDescriptor typeDescriptor = beanWrapper.getPropertyTypeDescriptor("labels");
System.out.println("属性描述器:" + typeDescriptor);
Object props = beanWrapper.getPropertyValue("props");
System.out.println("获取属性props值:" + (Map<String, Object>) props);
beanWrapper.setPropertyValue("name", "1234");
System.out.println("设置name属性值为 1234");
System.out.println(car);
PropertyValue weight = new PropertyValue("weight", 20D);
beanWrapper.setPropertyValue(weight);
System.out.println("设置weight属性值为 20");
System.out.println(car);
}
static class Car {
private String name;
private double weight;
private Map<String, Object> props;
private List<String> labels;
public Car() {
}
public void setName(String name) {
this.name = name;
}
public void setWeight(double weight) {
this.weight = weight;
}
public void setProps(Map<String, Object> props) {
this.props = props;
}
public void setLabels(List<String> labels) {
this.labels = labels;
}
public Map<String, Object> getProps() {
return props;
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", weight=" + weight +
", props=" + props +
", labels=" + labels +
'}';
}
}
}
PropertyEditorRegistry
主要作用:封装用户自定义属性编辑器和自带的编辑器。
public interface PropertyEditorRegistry {
// 注册用户自定义属性编辑器
void registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor);
// 注册用户自定义属性编辑器
void registerCustomEditor(@Nullable Class<?> requiredType, @Nullable String propertyPath, PropertyEditor propertyEditor);
// 查找属性编辑器
@Nullable
PropertyEditor findCustomEditor(@Nullable Class<?> requiredType, @Nullable String propertyPath);
}
类部分继承关系
除此之外,属性编辑器接口是JDK提供的。java.beans.PropertyEditor。
public interface PropertyEditor {
void setValue(Object value);
Object getValue();
boolean isPaintable();
void paintValue(java.awt.Graphics gfx, java.awt.Rectangle box);
String getJavaInitializationString();
String getAsText();
void setAsText(String text) throws java.lang.IllegalArgumentException;
String[] getTags();
java.awt.Component getCustomEditor();
boolean supportsCustomEditor();
void addPropertyChangeListener(PropertyChangeListener listener);
void removePropertyChangeListener(PropertyChangeListener listener);
}
自定义一个属性编辑器测试。
@DisplayName("自定义属性解析器及注册测试")
public class PropertyEditorRegistryTest {
@Test
public void customPropertyEditorRegistryTest() {
// 注册解析器
PropertyEditorRegistrySupport registrySupport = new PropertyEditorRegistrySupport();
registrySupport.registerCustomEditor(ConfigInfo.class, new CustomPropertyEditorRegistry());
// 解析属性测试
PropertyEditor customEditor = registrySupport.findCustomEditor(ConfigInfo.class, null);
customEditor.setAsText("treasure,soul");
ConfigInfo value = (ConfigInfo) customEditor.getValue();
System.out.println(value);
}
/**
* 自定义属性解析器
*/
static class CustomPropertyEditorRegistry extends PropertyEditorSupport {
private String text;
@Override
public void setAsText(String text) throws IllegalArgumentException {
this.text = text;
}
@Override
public Object getValue() {
ConfigInfo configInfo = new ConfigInfo();
configInfo.setWords(Arrays.stream(text.split(",")).collect(Collectors.toList()));
return configInfo;
}
}
static class ConfigInfo {
private List<String> words;
public ConfigInfo() {
}
public void setWords(List<String> words) {
this.words = words;
}
@Override
public String toString() {
return "ConfigInfo{" +
"words=" + words +
'}';
}
}
}
TypeConverter
主要作用:定义类型转换的方法。
源码中的方法
public interface TypeConverter {
// 转换值为要求的类型(如果有必要从String转换)
@Nullable
<T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType) throws TypeMismatchException;
@Nullable
<T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType,
@Nullable MethodParameter methodParam) throws TypeMismatchException;
@Nullable
<T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, @Nullable Field field)
throws TypeMismatchException;
@Nullable
default <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType,
@Nullable TypeDescriptor typeDescriptor) throws TypeMismatchException {
throw new UnsupportedOperationException("TypeDescriptor resolution not supported");
}
}
BeanWrapper
到此为止,基于上面三个接口,BeanWrapper组合了它们的能力:
属性读写、自定义属性解析器、类型转换。