spring源碼閱讀5,屬性編輯器

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

屬性編輯器

sun設(shè)計屬性編輯器主要是為IDE服務(wù)的,讓IDE能夠以可視化的方式設(shè)置JavaBean的屬性。核心接口是PropertyEditor,基本實現(xiàn)是java.beans.PropertyEditorSupport
屬性編輯器建將String類型轉(zhuǎn)換成我們需要的java對象。
Spring中有很多自定義的屬性編輯器,在spring-beans下下的org.springframework.beans.propertyeditors包里。

看一個典型的實現(xiàn)org.springframework.beans.propertyeditors.CustomBooleanEditor
用于轉(zhuǎn)換boolean類型

一般我們繼承實現(xiàn)屬性編輯器時,關(guān)注的核心是屬性編輯器的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屬性編輯器相關(guān)實現(xiàn)

注冊管理屬性編輯器接口
org.springframework.beans.PropertyEditorRegistry

image.png

默認(rèn)的實現(xiàn)org.springframework.beans.PropertyEditorRegistrySupport

PropertyEditorRegistrySupport 中創(chuàng)建了大量的默認(rèn)屬性編輯器。

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其繼承結(jié)構(gòu)如下

image.png

可以看到這個類實現(xiàn)了繼承了 PropertyEditorRegistrySupport
其中的TypeConverter接口定義如下,定義了具體類的轉(zhuǎn)換的接口

image.png

org.springframework.beans.PropertyAccessor定義如下,可以訪問一設(shè)置一個bean的各種屬性并設(shè)置

image.png

也就是說org.springframework.beans.BeanWrapperImpl這個類具有默認(rèn)注冊的屬性編輯器,可以轉(zhuǎn)換常見的格式,并且可以對java bean設(shè)置對應(yīng)的屬性。并且可以通過注冊新的屬性轉(zhuǎn)換器方法,增加新的轉(zhuǎn)換能力

具體例子

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值被正確的設(shè)置了
測試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

提示沒有轉(zhuǎn)換器,我們注冊一個轉(zhuǎn)換器進(jìn)去

測試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}
完成轉(zhuǎn)換

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容