Kava Pava Gava Tava Nava Zava Java

          everything about Java
          隨筆 - 15, 文章 - 0, 評(píng)論 - 1, 引用 - 0
          數(shù)據(jù)加載中……

          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() {
              }

          }



          posted on 2009-12-23 17:35 bing 閱讀(408) 評(píng)論(0)  編輯  收藏 所屬分類: GUI

          主站蜘蛛池模板: 六枝特区| 资溪县| 凤台县| 黑水县| 太谷县| 凌源市| 丰县| 宁明县| 兴宁市| 石泉县| 长白| 通河县| 汾西县| 珲春市| 莱州市| 莒南县| 兰考县| 玉山县| 青阳县| 如皋市| 兴海县| 台东市| 双桥区| 新邵县| 宁津县| 台南县| 兴海县| 阿城市| 平利县| 永康市| 墨竹工卡县| 碌曲县| 闸北区| 阿克苏市| 银川市| 安吉县| 阳春市| 福海县| 朝阳区| 岢岚县| 榆树市|