代码位置:
spring-beans:org.springframework.beans.BeanWrapper
查看其继承关系,可以发现其有三个主要的父接口和一个实现类,如下所示:
image.png
所以只要了解了这三个接口的能力,那么BeanWrapper的作用就差不多了。

PropertyAccessor

主要的作用:读写Bean的属性;
image.png

源码

  1. public interface PropertyAccessor {
  2. String NESTED_PROPERTY_SEPARATOR = ".";
  3. char NESTED_PROPERTY_SEPARATOR_CHAR = '.';
  4. String PROPERTY_KEY_PREFIX = "[";
  5. char PROPERTY_KEY_PREFIX_CHAR = '[';
  6. String PROPERTY_KEY_SUFFIX = "]";
  7. char PROPERTY_KEY_SUFFIX_CHAR = ']';
  8. // 判断属性是否可读,其实就是判断是否有get方法
  9. boolean isReadableProperty(String propertyName);
  10. // 判断属性是否可写,其实就是判断是否有set方法
  11. boolean isWritableProperty(String propertyName);
  12. // 获取属性类型
  13. @Nullable
  14. Class<?> getPropertyType(String propertyName) throws BeansException;
  15. // 获取TypeDescriptor,属性描述器
  16. @Nullable
  17. TypeDescriptor getPropertyTypeDescriptor(String propertyName) throws BeansException;
  18. // 获取属性的值
  19. @Nullable
  20. Object getPropertyValue(String propertyName) throws BeansException;
  21. // 设置属性的值
  22. void setPropertyValue(String propertyName, @Nullable Object value) throws BeansException;
  23. // 设置属性的值
  24. void setPropertyValue(PropertyValue pv) throws BeansException;
  25. // 批量设置属性的值
  26. void setPropertyValues(Map<?, ?> map) throws BeansException;
  27. // 批量设置属性的值
  28. void setPropertyValues(PropertyValues pvs) throws BeansException;
  29. // 批量设置属性的值
  30. void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown)
  31. throws BeansException;
  32. // 批量设置属性的值
  33. void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)
  34. throws BeansException;
  35. }

拿 BeanWrapper测试下

  1. @DisplayName("测试对Bean属性的读写能力")
  2. public class PropertyAccessorTest {
  3. @Test
  4. public void beanWrapperTest() {
  5. Car car = new Car();
  6. car.setName("笨笨");
  7. car.setWeight(1000D);
  8. car.setLabels(Lists.list("a,b,c"));
  9. car.setProps(Maps.newHashMap("color", "red"));
  10. BeanWrapper beanWrapper = new BeanWrapperImpl(car);
  11. Class<?> type = beanWrapper.getPropertyType("type");
  12. System.out.println("获取属性type:" + type);
  13. boolean readName = beanWrapper.isReadableProperty("name");
  14. System.out.println("属性name是否可读:" + readName);
  15. boolean writeWeight = beanWrapper.isWritableProperty("weight");
  16. System.out.println("属性weight是否可写:" + writeWeight);
  17. TypeDescriptor typeDescriptor = beanWrapper.getPropertyTypeDescriptor("labels");
  18. System.out.println("属性描述器:" + typeDescriptor);
  19. Object props = beanWrapper.getPropertyValue("props");
  20. System.out.println("获取属性props值:" + (Map<String, Object>) props);
  21. beanWrapper.setPropertyValue("name", "1234");
  22. System.out.println("设置name属性值为 1234");
  23. System.out.println(car);
  24. PropertyValue weight = new PropertyValue("weight", 20D);
  25. beanWrapper.setPropertyValue(weight);
  26. System.out.println("设置weight属性值为 20");
  27. System.out.println(car);
  28. }
  29. static class Car {
  30. private String name;
  31. private double weight;
  32. private Map<String, Object> props;
  33. private List<String> labels;
  34. public Car() {
  35. }
  36. public void setName(String name) {
  37. this.name = name;
  38. }
  39. public void setWeight(double weight) {
  40. this.weight = weight;
  41. }
  42. public void setProps(Map<String, Object> props) {
  43. this.props = props;
  44. }
  45. public void setLabels(List<String> labels) {
  46. this.labels = labels;
  47. }
  48. public Map<String, Object> getProps() {
  49. return props;
  50. }
  51. @Override
  52. public String toString() {
  53. return "Car{" +
  54. "name='" + name + '\'' +
  55. ", weight=" + weight +
  56. ", props=" + props +
  57. ", labels=" + labels +
  58. '}';
  59. }
  60. }
  61. }

PropertyEditorRegistry

主要作用:封装用户自定义属性编辑器和自带的编辑器。

  1. public interface PropertyEditorRegistry {
  2. // 注册用户自定义属性编辑器
  3. void registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor);
  4. // 注册用户自定义属性编辑器
  5. void registerCustomEditor(@Nullable Class<?> requiredType, @Nullable String propertyPath, PropertyEditor propertyEditor);
  6. // 查找属性编辑器
  7. @Nullable
  8. PropertyEditor findCustomEditor(@Nullable Class<?> requiredType, @Nullable String propertyPath);
  9. }

类部分继承关系
image.png

除此之外,属性编辑器接口是JDK提供的。java.beans.PropertyEditor。

  1. public interface PropertyEditor {
  2. void setValue(Object value);
  3. Object getValue();
  4. boolean isPaintable();
  5. void paintValue(java.awt.Graphics gfx, java.awt.Rectangle box);
  6. String getJavaInitializationString();
  7. String getAsText();
  8. void setAsText(String text) throws java.lang.IllegalArgumentException;
  9. String[] getTags();
  10. java.awt.Component getCustomEditor();
  11. boolean supportsCustomEditor();
  12. void addPropertyChangeListener(PropertyChangeListener listener);
  13. void removePropertyChangeListener(PropertyChangeListener listener);
  14. }

自定义一个属性编辑器测试。

  1. @DisplayName("自定义属性解析器及注册测试")
  2. public class PropertyEditorRegistryTest {
  3. @Test
  4. public void customPropertyEditorRegistryTest() {
  5. // 注册解析器
  6. PropertyEditorRegistrySupport registrySupport = new PropertyEditorRegistrySupport();
  7. registrySupport.registerCustomEditor(ConfigInfo.class, new CustomPropertyEditorRegistry());
  8. // 解析属性测试
  9. PropertyEditor customEditor = registrySupport.findCustomEditor(ConfigInfo.class, null);
  10. customEditor.setAsText("treasure,soul");
  11. ConfigInfo value = (ConfigInfo) customEditor.getValue();
  12. System.out.println(value);
  13. }
  14. /**
  15. * 自定义属性解析器
  16. */
  17. static class CustomPropertyEditorRegistry extends PropertyEditorSupport {
  18. private String text;
  19. @Override
  20. public void setAsText(String text) throws IllegalArgumentException {
  21. this.text = text;
  22. }
  23. @Override
  24. public Object getValue() {
  25. ConfigInfo configInfo = new ConfigInfo();
  26. configInfo.setWords(Arrays.stream(text.split(",")).collect(Collectors.toList()));
  27. return configInfo;
  28. }
  29. }
  30. static class ConfigInfo {
  31. private List<String> words;
  32. public ConfigInfo() {
  33. }
  34. public void setWords(List<String> words) {
  35. this.words = words;
  36. }
  37. @Override
  38. public String toString() {
  39. return "ConfigInfo{" +
  40. "words=" + words +
  41. '}';
  42. }
  43. }
  44. }

TypeConverter

主要作用:定义类型转换的方法。
image.png

源码中的方法

  1. public interface TypeConverter {
  2. // 转换值为要求的类型(如果有必要从String转换)
  3. @Nullable
  4. <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType) throws TypeMismatchException;
  5. @Nullable
  6. <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType,
  7. @Nullable MethodParameter methodParam) throws TypeMismatchException;
  8. @Nullable
  9. <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, @Nullable Field field)
  10. throws TypeMismatchException;
  11. @Nullable
  12. default <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType,
  13. @Nullable TypeDescriptor typeDescriptor) throws TypeMismatchException {
  14. throw new UnsupportedOperationException("TypeDescriptor resolution not supported");
  15. }
  16. }

BeanWrapper

到此为止,基于上面三个接口,BeanWrapper组合了它们的能力:
属性读写、自定义属性解析器、类型转换。