[spring]從頭開始-PropertyEditor
開發工具:IntelliJ IDEA 13
開發環境:jdk1.6.0_45
Framework:spring 3
一般bean 在 inject 時,一般String類型的資料都可以轉換為真實對應的型別,但若想要在當中做一些特別的加工處理的話,可以使用 CustomEditorConfigurer 這個類別來處理,以下就簡單來個範例如何做配置的動作,先簡單建立一個 bean
PropertyEditorBean.java
package foo.bar;
import org.springframework.context.support.GenericXmlApplicationContext;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.regex.Pattern;
/**
* Created by Hsu on 2014/7/22.
*/
public class PropertyEditorBean {
private byte[] bytes; // ByteArrayPropertyEditor
private Class cls; // ClassEditor
private Boolean trueOrFalse; // CustomBooleanEditor
private List<String> stringList; // CustomCollectionEditor
private Date date; // CustomDateEditor
private Float floatValue; // CustomNumberEditor
private File file; // FileEditor
private InputStream stream; // InputStreamEditor
private Locale locale; // LocaleEditor
private Pattern pattern; // PatternEditor
private Properties properties; // PropertiesEditor
private String trimString; // StringTrimmerEditor
private URL url; // URLEditor
public void setCls(Class cls) {
System.out.println("Setting class: " + cls.getName());
this.cls = cls;
}
public void setFile(File file) {
System.out.println("Setting file: " + file.getName());
this.file = file;
}
public void setLocale(Locale locale) {
System.out.println("Setting locale: " + locale.getDisplayName());
this.locale = locale;
}
public void setProperties(Properties properties) {
System.out.println("Loaded " + properties.size() + " properties");
this.properties = properties;
}
public void setUrl(URL url) {
System.out.println("Setting URL: " + url.toExternalForm());
this.url = url;
}
public void setBytes(byte[] bytes) {
System.out.println("Adding " + bytes.length + " bytes");
this.bytes = bytes;
}
public void setTrueOrFalse(Boolean trueOrFalse) {
System.out.println("Setting Boolean: " + trueOrFalse);
this.trueOrFalse = trueOrFalse;
}
public void setStringList(List<String> stringList) {
System.out.println("Setting string list with size: "
+ stringList.size());
this.stringList = stringList;
for (String string: stringList) {
System.out.println("String member: " + string);
}
}
public void setDate(Date date) {
System.out.println("Setting date: " + date);
this.date = date;
}
public void setFloatValue(Float floatValue) {
System.out.println("Setting float value: " + floatValue);
this.floatValue = floatValue;
}
public void setStream(InputStream stream) {
System.out.println("Setting stream: " + stream);
this.stream = stream;
}
public void setPattern(Pattern pattern) {
System.out.println("Setting pattern: " + pattern);
this.pattern = pattern;
}
public void setTrimString(String trimString) {
System.out.println("Setting trim string: " + trimString);
this.trimString = trimString;
}
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:builtin.xml");
ctx.refresh();
PropertyEditorBean bean =
(PropertyEditorBean) ctx.getBean("builtInSample");
}
}
上面有看到一些屬性已經準備好被inject,接著再設置spring configuration file
builtin.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.1.xsd">
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date">
<!-- 參數說明
CustomDateEditor(DateFormat dateFormat, boolean allowEmpty)
Create a new CustomDateEditor instance, using the given DateFormat for parsing and rendering.
-->
<bean class="org.springframework.beans.propertyeditors.CustomDateEditor">
<constructor-arg>
<bean class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-MM-dd" />
</bean>
</constructor-arg>
<constructor-arg value="true" />
</bean>
</entry>
<entry key="java.lang.String">
<!-- 參數說明
StringTrimmerEditor(boolean emptyAsNull)
Create a new StringTrimmerEditor.
-->
<bean
class="org.springframework.beans.propertyeditors.StringTrimmerEditor">
<constructor-arg value="true" />
</bean>
</entry>
</map>
</property>
</bean>
<bean id="builtInSample" class="foo.bar.PropertyEditorBean">
<property name="bytes">
<value>Hello World</value>
</property>
<property name="cls">
<value>java.lang.String</value>
</property>
<property name="trueOrFalse">
<value>true</value>
</property>
<property name="stringList">
<util:list>
<value>String member 1</value>
<value>String member 2</value>
</util:list>
</property>
<!--
將轉換為 SimpleDateFormat 型態
-->
<property name="date">
<value>2011-12-29</value>
</property>
<property name="floatValue">
<value>123.45678</value>
</property>
<property name="file">
<value>classpath:test.txt</value>
</property>
<property name="stream">
<value>classpath:test.txt</value>
</property>
<property name="locale">
<value>en_US</value>
</property>
<property name="pattern">
<value>a*b</value>
</property>
<property name="properties">
<value>
name=foo
age=19
</value>
</property>
<!-- 因為前面有自訂了 CustomEditorConfigurer 的 customEditors 中的 java.lang.String
系統會自動將字串前後空格去除
-->
<property name="trimString">
<value> String need trimming </value>
</property>
<property name="url">
<value>http://www.springframework.org</value>
</property>
</bean>
</beans>
程式的執行結果:
Adding 11 bytes
Setting class: java.lang.String
Setting Boolean: true
Setting string list with size: 2
String member: String member 1
String member: String member 2
Setting date: Thu Dec 29 00:00:00 CST 2011
Setting float value: 123.45678
Setting file: test.txt
Setting stream: java.io.BufferedInputStream@50269997
Setting locale: 英文 (美國)
Setting pattern: a*b
Loaded 2 properties
Setting trim string: String need trimming q 11
Setting URL: http://www.springframework.org
值得注意的是 Setting date及 Setting trim string這兩個部分,其中的值已經藉由我們使用 CustomEditorConfigurer 而改變成我們所想要的型態!!! spring 還有許多內建的 PropertyEditors
from: http://docs.spring.io/spring/docs/2.0.x/reference/validation.html
Class | Explanation |
ByteArrayPropertyEditor | Editor for byte arrays. Strings will simply be converted to their corresponding byte representations. Registered by default byBeanWrapperImpl. |
ClassEditor | Parses Strings representing classes to actual classes and the other way around. When a class is not found, anIllegalArgumentException is thrown. Registered by default by BeanWrapperImpl. |
CustomBooleanEditor | Customizable property editor for Boolean properties. Registered by default by BeanWrapperImpl, but, can be overridden by registering custom instance of it as custom editor. |
CustomCollectionEditor | Property editor for Collections, converting any source Collection to a given target Collection type. |
CustomDateEditor | Customizable property editor for java.util.Date, supporting a custom DateFormat. NOT registered by default. Must be user registered as needed with appropriate format. |
CustomNumberEditor | Customizable property editor for any Number subclass like Integer, Long, Float, Double. Registered by default by BeanWrapperImpl, but can be overridden by registering custom instance of it as a custom editor. |
FileEditor | Capable of resolving Strings to java.io.File objects. Registered by default by BeanWrapperImpl. |
InputStreamEditor | One-way property editor, capable of taking a text string and producing (via an intermediate ResourceEditor and Resource) anInputStream, so InputStream properties may be directly set as Strings. Note that the default usage will not close the InputStream for you! Registered by default by BeanWrapperImpl. |
LocaleEditor | Capable of resolving Strings to Locale objects and vice versa (the String format is [language]_[country]_[variant], which is the same thing the toString() method of Locale provides). Registered by default by BeanWrapperImpl. |
PatternEditor | Capable of resolving Strings to JDK 1.5 Pattern objects and vice versa. |
PropertiesEditor | Capable of converting Strings (formatted using the format as defined in the Javadoc for the java.lang.Properties class) to Propertiesobjects. Registered by default by BeanWrapperImpl. |
StringTrimmerEditor | Property editor that trims Strings. Optionally allows transforming an empty string into a null value. NOT registered by default; must be user registered as needed. |
URLEditor | Capable of resolving a String representation of a URL to an actual URL object. Registered by default by BeanWrapperImpl. |
以上各自有自己不同的用途,可以自己運用,但如果上述的 PropertyEditors 沒有適合的,那就Creating a Custom PropertyEditor ,我們來看一下簡單的範例,先建立一個 class
Name.java
package foo.bar;
/**
* Created by Hsu on 2014/7/15.
*/
public class Name {
private String firstName;
private String lastName;
public Name() {
}
public Name(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
//最後配合 System.out.println 輸出的結果
public String toString() {
return "First name: " + firstName + " - Last name: " + lastName;
}
}
可以看到上面設定了兩個屬性 first name and last name,現在我們打算inject 一個String,中間的規則是遇到空字串後自動分成 first name and last name,並將其inject,我們可以必須建立專屬的 PropertyEditor,使用 extends PropertyEditorSupport 來完成,下面就是範例類別:
NamePropertyEditor.java
package foo.bar;
import java.beans.PropertyEditorSupport;
/**
* Created by Hsu on 2014/7/15.
*/
public class NamePropertyEditor extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
String[] name = text.split("\\s");
Name result = new Name(name[0], name[1]);
setValue(result);
}
}
上面的類別我們繼承了 PropertyEditorSupport 這個類,並改寫其中的 setAsText 的方法,程式內的邏輯為,將輸入的String text,再藉由 setValue 將轉化後 Name result 的結果 inject,如此一來我們已經完成了自己的 PropertyEditor,但是要使用時,必須要告訴 spring 要使用他,所以必須要 register the editor in Spring’s
ApplicationContext,底下的 spring configuration file 就是配置方式:
spring-config.xml
..
..標頭的部分省略
<bean name="customEditorConfigurer"
class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<!-- 要執行轉換的類別 -->
<entry key="foo.bar.Name">
<!-- 自訂的 PropertyEditor 轉換邏輯在這兒-->
<bean class="foo.bar.NamePropertyEditor"/>
</entry>
</map>
</property>
</bean>
<bean id="exampleBean" class="foo.bar.CustomEditorExample">
<property name="name">
<value>Clarence Ho</value>
</property>
</bean>
..結尾省略
最後我們來建立一個演繹類別 CustomEditorExample
CustomEditorExample.java
package foo.bar;
import org.springframework.context.support.GenericXmlApplicationContext;
/**
* Created by Hsu on 2014/7/15.
*/
public class CustomEditorExample {
private Name name;
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("classpath:spring-config.xml");
ctx.refresh();
CustomEditorExample bean = (CustomEditorExample) ctx.getBean("exampleBean");
System.out.println(bean.getName());
}
public Name getName() {
return name;
}
public void setName(Name name) {
this.name = name;
}
}
程式在注入時,因為我們已經有使用 xml 將自訂的 CustomPropertyEditor 註冊到 ApplicationContext,所以當inject 遇到 foo.bar.Name 類別的資料時,就會去 RUN 我們的規則,所以最後輸出的結果為:
First name: Clarence - Last name: Ho
以上就是採用xml設定並搭配我們自訂的 PropertyEditor 的方式,當然也可以使用寫 java code 的方式去做設定喔。