代码位置:
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);// 获取属性类型@NullableClass<?> getPropertyType(String propertyName) throws BeansException;// 获取TypeDescriptor,属性描述器@NullableTypeDescriptor getPropertyTypeDescriptor(String propertyName) throws BeansException;// 获取属性的值@NullableObject 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 {@Testpublic 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;}@Overridepublic 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);// 查找属性编辑器@NullablePropertyEditor 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 {@Testpublic 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;@Overridepublic void setAsText(String text) throws IllegalArgumentException {this.text = text;}@Overridepublic 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;}@Overridepublic 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;@Nullabledefault <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType,@Nullable TypeDescriptor typeDescriptor) throws TypeMismatchException {throw new UnsupportedOperationException("TypeDescriptor resolution not supported");}}
BeanWrapper
到此为止,基于上面三个接口,BeanWrapper组合了它们的能力:
属性读写、自定义属性解析器、类型转换。
