spring源码阅读5,属性编辑器

p, li { white-space: pre-wrap; }

属性编辑器

sun设计属性编辑器主要是为IDE服务的,让IDE能够以可视化的方式设置JavaBean的属性。核心接口是PropertyEditor,基本实现是java.beans.PropertyEditorSupport
属性编辑器建将String类型转换成我们需要的java对象。
Spring中有很多自定义的属性编辑器,在spring-beans下下的org.springframework.beans.propertyeditors包里。

看一个典型的实现org.springframework.beans.propertyeditors.CustomBooleanEditor
用于转换boolean类型

一般我们继承实现属性编辑器时,关注的核心是属性编辑器的setAsText方法

public static final String VALUE_TRUE = "true";
public static final String VALUE_FALSE = "false";

public static final String VALUE_ON = "on";
public static final String VALUE_OFF = "off";

public static final String VALUE_YES = "yes";
public static final String VALUE_NO = "no";

public static final String VALUE_1 = "1";
public static final String VALUE_0 = "0";

@Override
public void setAsText(String text) throws IllegalArgumentException {
String input = (text != null ? text.trim() : null);
if (this.allowEmpty && !StringUtils.hasLength(input)) {
// Treat empty String as null value.
setValue(null);
}
else if (this.trueString != null && this.trueString.equalsIgnoreCase(input)) {
setValue(Boolean.TRUE);
}
else if (this.falseString != null && this.falseString.equalsIgnoreCase(input)) {
setValue(Boolean.FALSE);
}
else if (this.trueString == null &&
(VALUE_TRUE.equalsIgnoreCase(input) || VALUE_ON.equalsIgnoreCase(input) ||
VALUE_YES.equalsIgnoreCase(input) || VALUE_1.equals(input))) {
setValue(Boolean.TRUE);
}
else if (this.falseString == null &&
(VALUE_FALSE.equalsIgnoreCase(input) || VALUE_OFF.equalsIgnoreCase(input) ||
VALUE_NO.equalsIgnoreCase(input) || VALUE_0.equals(input))) {
setValue(Boolean.FALSE);
}
else {
throw new IllegalArgumentException("Invalid boolean value [" + text + "]");
}
}

也就是实说 true, on yes 1 可以被解析为true。

spring属性编辑器相关实现

注册管理属性编辑器接口
org.springframework.beans.PropertyEditorRegistry

spring源码阅读5,属性编辑器_第1张图片
image.png

默认的实现org.springframework.beans.PropertyEditorRegistrySupport

PropertyEditorRegistrySupport 中创建了大量的默认属性编辑器。

private void createDefaultEditors() {
this.defaultEditors = new HashMap<>(64);

// Simple editors, without parameterization capabilities.
// The JDK does not contain a default editor for any of these target types.
this.defaultEditors.put(Charset.class, new CharsetEditor());
this.defaultEditors.put(Class.class, new ClassEditor());
this.defaultEditors.put(Class[].class, new ClassArrayEditor());
this.defaultEditors.put(Currency.class, new CurrencyEditor());
this.defaultEditors.put(File.class, new FileEditor());
this.defaultEditors.put(InputStream.class, new InputStreamEditor());
this.defaultEditors.put(InputSource.class, new InputSourceEditor());
this.defaultEditors.put(Locale.class, new LocaleEditor());
this.defaultEditors.put(Path.class, new PathEditor());
this.defaultEditors.put(Pattern.class, new PatternEditor());
this.defaultEditors.put(Properties.class, new PropertiesEditor());
this.defaultEditors.put(Reader.class, new ReaderEditor());
this.defaultEditors.put(Resource[].class, new ResourceArrayPropertyEditor());
this.defaultEditors.put(TimeZone.class, new TimeZoneEditor());
this.defaultEditors.put(URI.class, new URIEditor());
this.defaultEditors.put(URL.class, new URLEditor());
this.defaultEditors.put(UUID.class, new UUIDEditor());
this.defaultEditors.put(ZoneId.class, new ZoneIdEditor());

// Default instances of collection editors.
// Can be overridden by registering custom instances of those as custom editors.
this.defaultEditors.put(Collection.class, new CustomCollectionEditor(Collection.class));
this.defaultEditors.put(Set.class, new CustomCollectionEditor(Set.class));
this.defaultEditors.put(SortedSet.class, new CustomCollectionEditor(SortedSet.class));
this.defaultEditors.put(List.class, new CustomCollectionEditor(List.class));
this.defaultEditors.put(SortedMap.class, new CustomMapEditor(SortedMap.class));

// Default editors for primitive arrays.
this.defaultEditors.put(byte[].class, new ByteArrayPropertyEditor());
this.defaultEditors.put(char[].class, new CharArrayPropertyEditor());

// The JDK does not contain a default editor for char!
this.defaultEditors.put(char.class, new CharacterEditor(false));
this.defaultEditors.put(Character.class, new CharacterEditor(true));

// Spring's CustomBooleanEditor accepts more flag values than the JDK's default editor.
this.defaultEditors.put(boolean.class, new CustomBooleanEditor(false));
this.defaultEditors.put(Boolean.class, new CustomBooleanEditor(true));

// The JDK does not contain default editors for number wrapper types!
// Override JDK primitive number editors with our own CustomNumberEditor.
this.defaultEditors.put(byte.class, new CustomNumberEditor(Byte.class, false));
this.defaultEditors.put(Byte.class, new CustomNumberEditor(Byte.class, true));
this.defaultEditors.put(short.class, new CustomNumberEditor(Short.class, false));
this.defaultEditors.put(Short.class, new CustomNumberEditor(Short.class, true));
this.defaultEditors.put(int.class, new CustomNumberEditor(Integer.class, false));
this.defaultEditors.put(Integer.class, new CustomNumberEditor(Integer.class, true));
this.defaultEditors.put(long.class, new CustomNumberEditor(Long.class, false));
this.defaultEditors.put(Long.class, new CustomNumberEditor(Long.class, true));
this.defaultEditors.put(float.class, new CustomNumberEditor(Float.class, false));
this.defaultEditors.put(Float.class, new CustomNumberEditor(Float.class, true));
this.defaultEditors.put(double.class, new CustomNumberEditor(Double.class, false));
this.defaultEditors.put(Double.class, new CustomNumberEditor(Double.class, true));
this.defaultEditors.put(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, true));
this.defaultEditors.put(BigInteger.class, new CustomNumberEditor(BigInteger.class, true));

// Only register config value editors if explicitly requested.
if (this.configValueEditorsActive) {
StringArrayPropertyEditor sae = new StringArrayPropertyEditor();
this.defaultEditors.put(String[].class, sae);
this.defaultEditors.put(short[].class, sae);
this.defaultEditors.put(int[].class, sae);
this.defaultEditors.put(long[].class, sae);
}
}

spring中一个重要的类 org.springframework.beans.BeanWrapperImpl其继承结构如下

spring源码阅读5,属性编辑器_第2张图片
image.png

可以看到这个类实现了继承了 PropertyEditorRegistrySupport
其中的TypeConverter接口定义如下,定义了具体类的转换的接口

spring源码阅读5,属性编辑器_第3张图片
image.png

org.springframework.beans.PropertyAccessor定义如下,可以访问一设置一个bean的各种属性并设置

spring源码阅读5,属性编辑器_第4张图片
image.png

也就是说org.springframework.beans.BeanWrapperImpl这个类具有默认注册的属性编辑器,可以转换常见的格式,并且可以对java bean设置对应的属性。并且可以通过注册新的属性转换器方法,增加新的转换能力

具体例子

class TestBean{
String name;
Date brith;
Integer age;
boolean top;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Date getBrith() {
return brith;
}

public void setBrith(Date brith) {
this.brith = brith;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

public boolean isTop() {
return top;
}

public void setTop(boolean top) {
this.top = top;
}

@Override
public String toString() {
return "TestBean{" +
"name='" + name + '\'' +
", brith=" + brith +
", age=" + age +
", top=" + top +
'}';
}
}

测试1,

TestBean testBean = new TestBean();
BeanWrapper beanWrapper = new BeanWrapperImpl(testBean);
beanWrapper.setPropertyValue("top", "1");
System.out.println(testBean);

输出为

TestBean{name='null', brith=null, age=null, top=true}

可以看到top值被正确的设置了
测试2

TestBean testBean = new TestBean();
BeanWrapper beanWrapper = new BeanWrapperImpl(testBean);
beanWrapper.setPropertyValue("brith", "2017-01-01");
System.out.println(testBean);

输出为

Cannot convert value of type [java.lang.String] to required type [java.util.Date] for property 'brith': no matching editors or conversion strategy found

提示没有转换器,我们注册一个转换器进去

测试3

TestBean testBean = new TestBean();
BeanWrapper beanWrapper = new BeanWrapperImpl(testBean);
beanWrapper.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
beanWrapper.setPropertyValue("brith", "2017-01-01");
System.out.println(testBean);

输出为

TestBean{name='null', brith=Sun Jan 01 00:00:00 CST 2017, age=null, top=false}
完成转换

你可能感兴趣的:(spring源码阅读5,属性编辑器)