Exploring Vaadin (4) 閱讀 com.vaadin.data.util.MethodProperty 源代碼
閱讀 MethodProperty 的目的是因?yàn)檫@個(gè)類是 Property,同時(shí)處理 Bean 的屬性。本以為可能會(huì)牽扯到 Vaadin 處理類型轉(zhuǎn)換的地方,可以了解一下 Vaadin 是如何操作的。結(jié)果發(fā)現(xiàn)這里的確進(jìn)行了類型轉(zhuǎn)換,見setValue 。但是,這種類型轉(zhuǎn)換的方法非常的粗糙以及不可靠:就是如果目標(biāo)類型有一個(gè)構(gòu)造函數(shù),僅僅接受一個(gè)String作為參數(shù),則把要set的源數(shù)據(jù)先 toString()然后調(diào)用這個(gè)構(gòu)造函數(shù),來(lái)獲得一個(gè)目標(biāo)類型。如此,應(yīng)該在大多數(shù)時(shí)候?qū)?MethodProperty 和一個(gè) com.vaadin.data.util.PropertyFormatter 結(jié)合起來(lái)使用。這個(gè)才是用來(lái)進(jìn)行明確的類型轉(zhuǎn)換的。下面采用注釋的方式記錄閱讀源代碼的心得。注意代碼已經(jīng)被去掉了。
/**
* 源文件注釋:這個(gè)類是專用于 getter / setter 訪問(wèn)的 bean property 的。使用 Property 接口訪問(wèn)將直接操作
* 牽連的 Bean 的屬性。要求getter / setter類型正確。可以僅有g(shù)etter沒(méi)有setter,這樣認(rèn)為是只讀。
* 實(shí)現(xiàn)了ValieChangeNotifier接口,可并不是真的自動(dòng)知道是不是 bean 的 getter 方法會(huì)得到新的值,而只是在
* 每一次 setValue 被調(diào)用的時(shí)候通知 listener
* @version
* 6.1.5
*/
public class MethodProperty implements Property, Property.ValueChangeNotifier,
Property.ReadOnlyStatusChangeNotifier {
//帶有g(shù)etter/setter的那個(gè) instance
private transient Object instance;
// getter 和 setter 的參數(shù)隊(duì)列
private transient Object[] setArgs, getArgs;
private boolean readOnly;
// getter / setter methods
private transient Method setMethod, getMethod;
// 如果 setter 方法有多個(gè)參數(shù),這個(gè)是值參數(shù)的 index
private int setArgumentIndex;
// 屬性的類型
private transient Class<?> type;
private LinkedList readOnlyStatusChangeListeners = null;
private LinkedList valueChangeListeners = null;
// 序列化,可以處理 Method,就是把名字輸出。
private void writeObject(java.io.ObjectOutputStream out) throws IOException {};
private void readObject(java.io.ObjectInputStream in) throws IOException,
ClassNotFoundException {}
};
/**
* 自動(dòng)初始化方法,應(yīng)該是供正常使用的。
* 用這種方法建立 MethodProperty,getter 沒(méi)有參數(shù),setter 只有一個(gè)值參數(shù),(最基本形式)
* 如果沒(méi)有 setter,則 property 只讀。
*/
public MethodProperty(Object instance, String beanPropertyName) {
final Class beanClass = instance.getClass();
// 這里 beanPropertyName 因該是首字母大寫,沒(méi)有 get/set/is 之類的。如果首字母沒(méi)有大寫,本方法會(huì)修正。
// 嘗試各個(gè)方式找到 getter。
// 通過(guò) getter 的返回類型得到 type
// 嘗試各個(gè)方式找到 setter
// 如果 type 是基本類型,轉(zhuǎn)成對(duì)應(yīng)的類
// 設(shè)置調(diào)用參數(shù),readonly, instance
}
/** 只是一些簡(jiǎn)化版初始化方法 */
public MethodProperty(Class type, Object instance, String getMethodName,
String setMethodName) {
}
public MethodProperty(Class type, Object instance, Method getMethod,
Method setMethod) {
}
/**
* 初始化,提供全部?jī)?nèi)部屬性。平時(shí)應(yīng)該不會(huì)用到。
*/
public MethodProperty(Class type, Object instance, String getMethodName,
String setMethodName, Object[] getArgs, Object[] setArgs,
int setArgumentIndex) {
// 一些參數(shù)正確檢查
// 設(shè)置類型
// 從 instance.getClass().getMethods 中,根據(jù)名字,返回類型,參數(shù)個(gè)數(shù),各個(gè)參數(shù)的類型,找到 getter。
// 總之,getter 可以不是最常見的無(wú)參數(shù) getter,可以是任何 method。從這點(diǎn)上說(shuō),MethodProperty 這個(gè)名字
// 是很貼切的。
// 再找 setter,同樣過(guò)程。
// 再處理 primitive 類型
// 最后設(shè)置 arguments, readOnly, instance
}
/** 另一個(gè)版本的初始化,處理相同。
*/
public MethodProperty(Class type, Object instance, Method getMethod,
Method setMethod, Object[] getArgs, Object[] setArgs,
int setArgumentIndex) {
}
// 就是簡(jiǎn)單的 getter
public final Class getType() {
return type;
}
public boolean isReadOnly() {
return readOnly;
}
// 調(diào)用,直接去從 instance 得到值。這里面沒(méi)有緩沖。
public Object getValue() {
try {
return getMethod.invoke(instance, getArgs);
} catch (final Throwable e) {
throw new MethodProperty.MethodException(e);
}
}
// 見簡(jiǎn)版實(shí)現(xiàn)
public String toString() {
// 簡(jiǎn)而言之: getValue().toString();
}
/** 設(shè)置 getter / setter 的參數(shù)隊(duì)列
*/
public void setArguments(Object[] getArgs, Object[] setArgs,
int setArgumentIndex) {
// 就是拷貝出來(lái)。這樣就不會(huì)被別人修改。
}
/**
* Sets the value of the property. This method supports setting from
* <code>String</code>s if either <code>String</code> is directly assignable
* to property type, or the type class contains a string constructor.
*
* @param newValue
* the New value of the property.
* @throws <code>Property.ReadOnlyException</code> if the object is in
* read-only mode.
* @throws <code>Property.ConversionException</code> if
* <code>newValue</code> can't be converted into the Property's
* native type directly or through <code>String</code>.
* @see #invokeSetMethod(Object)
*/
public void setValue(Object newValue) throws Property.ReadOnlyException,
Property.ConversionException {
// 如果 readonly,拋出異常。
// 下面試圖直接通過(guò) invokeSetMethod 進(jìn)行設(shè)置。判斷的條件是 isAssignableFrom,也就是同類,接口實(shí)現(xiàn),父類,或者
// 等同的 primitive / 類,等等,總之就是可以直接賦值。這里 type 是在初始化的時(shí)候計(jì)算的 getMethod 的返回值,并且保證
// 對(duì)應(yīng)的 setMethod 也接受這個(gè)類型的值。
if (newValue == null || type.isAssignableFrom(newValue.getClass())) {
invokeSetMethod(newValue);
} else {
// 否則,看看該被 set 的類型有沒(méi)有一個(gè)只有一個(gè) string 作為參數(shù)的初始化函數(shù),如果有,就用 newValue.toString() 來(lái)初始化。這個(gè)
// 可是有些主觀啊。這樣看起來(lái)恐怕 vaadin 并沒(méi)有提供一個(gè)類型轉(zhuǎn)換框架。
Object value;
try {
// Gets the string constructor
final Constructor constr = getType().getConstructor(
new Class[] { String.class });
value = constr
.newInstance(new Object[] { newValue.toString() });
} catch (final java.lang.Exception e) {
throw new Property.ConversionException(e);
}
// 總之調(diào)用 setter
invokeSetMethod(value);
}
// 通知各個(gè) listener
fireValueChange();
}
/**調(diào)用 setter */
private void invokeSetMethod(Object value) {
// 調(diào)用 setter,不管是只有一個(gè)參數(shù)還是多個(gè)參數(shù)。
}
// 設(shè)置只讀狀態(tài)。但是否可以不只讀還要看有沒(méi)有setter
public void setReadOnly(boolean newStatus) {
}
/** 調(diào)用 getter / setter 時(shí)候拋出的異常,再包裝一下。
*/
public class MethodException extends RuntimeException {
}
/* 只讀狀態(tài)改變事件
*/
private class ReadOnlyStatusChangeEvent extends java.util.EventObject
implements Property.ReadOnlyStatusChangeEvent {
}
/** 下面的看名字就知道了,不再描述了。
*/
public void addListener(Property.ReadOnlyStatusChangeListener listener) {
}
public void removeListener(Property.ReadOnlyStatusChangeListener listener) {
}
private void fireReadOnlyStatusChange() {
}
private class ValueChangeEvent extends java.util.EventObject implements
}
public void addListener(ValueChangeListener listener) {
}
public void removeListener(ValueChangeListener listener) {
}
// 這里說(shuō)一句,valueChange事件是可以主動(dòng)去 fire 的。
public void fireValueChange() {
}
}
* 源文件注釋:這個(gè)類是專用于 getter / setter 訪問(wèn)的 bean property 的。使用 Property 接口訪問(wèn)將直接操作
* 牽連的 Bean 的屬性。要求getter / setter類型正確。可以僅有g(shù)etter沒(méi)有setter,這樣認(rèn)為是只讀。
* 實(shí)現(xiàn)了ValieChangeNotifier接口,可并不是真的自動(dòng)知道是不是 bean 的 getter 方法會(huì)得到新的值,而只是在
* 每一次 setValue 被調(diào)用的時(shí)候通知 listener
* @version
* 6.1.5
*/
public class MethodProperty implements Property, Property.ValueChangeNotifier,
Property.ReadOnlyStatusChangeNotifier {
//帶有g(shù)etter/setter的那個(gè) instance
private transient Object instance;
// getter 和 setter 的參數(shù)隊(duì)列
private transient Object[] setArgs, getArgs;
private boolean readOnly;
// getter / setter methods
private transient Method setMethod, getMethod;
// 如果 setter 方法有多個(gè)參數(shù),這個(gè)是值參數(shù)的 index
private int setArgumentIndex;
// 屬性的類型
private transient Class<?> type;
private LinkedList readOnlyStatusChangeListeners = null;
private LinkedList valueChangeListeners = null;
// 序列化,可以處理 Method,就是把名字輸出。
private void writeObject(java.io.ObjectOutputStream out) throws IOException {};
private void readObject(java.io.ObjectInputStream in) throws IOException,
ClassNotFoundException {}
};
/**
* 自動(dòng)初始化方法,應(yīng)該是供正常使用的。
* 用這種方法建立 MethodProperty,getter 沒(méi)有參數(shù),setter 只有一個(gè)值參數(shù),(最基本形式)
* 如果沒(méi)有 setter,則 property 只讀。
*/
public MethodProperty(Object instance, String beanPropertyName) {
final Class beanClass = instance.getClass();
// 這里 beanPropertyName 因該是首字母大寫,沒(méi)有 get/set/is 之類的。如果首字母沒(méi)有大寫,本方法會(huì)修正。
// 嘗試各個(gè)方式找到 getter。
// 通過(guò) getter 的返回類型得到 type
// 嘗試各個(gè)方式找到 setter
// 如果 type 是基本類型,轉(zhuǎn)成對(duì)應(yīng)的類
// 設(shè)置調(diào)用參數(shù),readonly, instance
}
/** 只是一些簡(jiǎn)化版初始化方法 */
public MethodProperty(Class type, Object instance, String getMethodName,
String setMethodName) {
}
public MethodProperty(Class type, Object instance, Method getMethod,
Method setMethod) {
}
/**
* 初始化,提供全部?jī)?nèi)部屬性。平時(shí)應(yīng)該不會(huì)用到。
*/
public MethodProperty(Class type, Object instance, String getMethodName,
String setMethodName, Object[] getArgs, Object[] setArgs,
int setArgumentIndex) {
// 一些參數(shù)正確檢查
// 設(shè)置類型
// 從 instance.getClass().getMethods 中,根據(jù)名字,返回類型,參數(shù)個(gè)數(shù),各個(gè)參數(shù)的類型,找到 getter。
// 總之,getter 可以不是最常見的無(wú)參數(shù) getter,可以是任何 method。從這點(diǎn)上說(shuō),MethodProperty 這個(gè)名字
// 是很貼切的。
// 再找 setter,同樣過(guò)程。
// 再處理 primitive 類型
// 最后設(shè)置 arguments, readOnly, instance
}
/** 另一個(gè)版本的初始化,處理相同。
*/
public MethodProperty(Class type, Object instance, Method getMethod,
Method setMethod, Object[] getArgs, Object[] setArgs,
int setArgumentIndex) {
}
// 就是簡(jiǎn)單的 getter
public final Class getType() {
return type;
}
public boolean isReadOnly() {
return readOnly;
}
// 調(diào)用,直接去從 instance 得到值。這里面沒(méi)有緩沖。
public Object getValue() {
try {
return getMethod.invoke(instance, getArgs);
} catch (final Throwable e) {
throw new MethodProperty.MethodException(e);
}
}
// 見簡(jiǎn)版實(shí)現(xiàn)
public String toString() {
// 簡(jiǎn)而言之: getValue().toString();
}
/** 設(shè)置 getter / setter 的參數(shù)隊(duì)列
*/
public void setArguments(Object[] getArgs, Object[] setArgs,
int setArgumentIndex) {
// 就是拷貝出來(lái)。這樣就不會(huì)被別人修改。
}
/**
* Sets the value of the property. This method supports setting from
* <code>String</code>s if either <code>String</code> is directly assignable
* to property type, or the type class contains a string constructor.
*
* @param newValue
* the New value of the property.
* @throws <code>Property.ReadOnlyException</code> if the object is in
* read-only mode.
* @throws <code>Property.ConversionException</code> if
* <code>newValue</code> can't be converted into the Property's
* native type directly or through <code>String</code>.
* @see #invokeSetMethod(Object)
*/
public void setValue(Object newValue) throws Property.ReadOnlyException,
Property.ConversionException {
// 如果 readonly,拋出異常。
// 下面試圖直接通過(guò) invokeSetMethod 進(jìn)行設(shè)置。判斷的條件是 isAssignableFrom,也就是同類,接口實(shí)現(xiàn),父類,或者
// 等同的 primitive / 類,等等,總之就是可以直接賦值。這里 type 是在初始化的時(shí)候計(jì)算的 getMethod 的返回值,并且保證
// 對(duì)應(yīng)的 setMethod 也接受這個(gè)類型的值。
if (newValue == null || type.isAssignableFrom(newValue.getClass())) {
invokeSetMethod(newValue);
} else {
// 否則,看看該被 set 的類型有沒(méi)有一個(gè)只有一個(gè) string 作為參數(shù)的初始化函數(shù),如果有,就用 newValue.toString() 來(lái)初始化。這個(gè)
// 可是有些主觀啊。這樣看起來(lái)恐怕 vaadin 并沒(méi)有提供一個(gè)類型轉(zhuǎn)換框架。
Object value;
try {
// Gets the string constructor
final Constructor constr = getType().getConstructor(
new Class[] { String.class });
value = constr
.newInstance(new Object[] { newValue.toString() });
} catch (final java.lang.Exception e) {
throw new Property.ConversionException(e);
}
// 總之調(diào)用 setter
invokeSetMethod(value);
}
// 通知各個(gè) listener
fireValueChange();
}
/**調(diào)用 setter */
private void invokeSetMethod(Object value) {
// 調(diào)用 setter,不管是只有一個(gè)參數(shù)還是多個(gè)參數(shù)。
}
// 設(shè)置只讀狀態(tài)。但是否可以不只讀還要看有沒(méi)有setter
public void setReadOnly(boolean newStatus) {
}
/** 調(diào)用 getter / setter 時(shí)候拋出的異常,再包裝一下。
*/
public class MethodException extends RuntimeException {
}
/* 只讀狀態(tài)改變事件
*/
private class ReadOnlyStatusChangeEvent extends java.util.EventObject
implements Property.ReadOnlyStatusChangeEvent {
}
/** 下面的看名字就知道了,不再描述了。
*/
public void addListener(Property.ReadOnlyStatusChangeListener listener) {
}
public void removeListener(Property.ReadOnlyStatusChangeListener listener) {
}
private void fireReadOnlyStatusChange() {
}
private class ValueChangeEvent extends java.util.EventObject implements
}
public void addListener(ValueChangeListener listener) {
}
public void removeListener(ValueChangeListener listener) {
}
// 這里說(shuō)一句,valueChange事件是可以主動(dòng)去 fire 的。
public void fireValueChange() {
}
}
posted on 2009-12-23 17:35 bing 閱讀(408) 評(píng)論(0) 編輯 收藏 所屬分類: GUI