Kava Pava Gava Tava Nava Zava Java

          everything about Java
          隨筆 - 15, 文章 - 0, 評論 - 1, 引用 - 0
          數據加載中……

          Exploring Vaadin (4) 閱讀 com.vaadin.data.util.MethodProperty 源代碼

          閱讀 MethodProperty 的目的是因為這個類是 Property,同時處理 Bean 的屬性。本以為可能會牽扯到 Vaadin 處理類型轉換的地方,可以了解一下 Vaadin 是如何操作的。結果發現這里的確進行了類型轉換,見setValue 。但是,這種類型轉換的方法非常的粗糙以及不可靠:就是如果目標類型有一個構造函數,僅僅接受一個String作為參數,則把要set的源數據先 toString()然后調用這個構造函數,來獲得一個目標類型。如此,應該在大多數時候將 MethodProperty 和一個 com.vaadin.data.util.PropertyFormatter 結合起來使用。這個才是用來進行明確的類型轉換的。下面采用注釋的方式記錄閱讀源代碼的心得。注意代碼已經被去掉了。

          /**
           * 源文件注釋:這個類是專用于 getter / setter 訪問的 bean property 的。使用 Property 接口訪問將直接操作
           * 牽連的 Bean 的屬性。要求getter / setter類型正確。可以僅有getter沒有setter,這樣認為是只讀。
           * 實現了ValieChangeNotifier接口,可并不是真的自動知道是不是 bean 的 getter 方法會得到新的值,而只是在
           * 每一次 setValue 被調用的時候通知 listener
           * 
          @version
           * 6.1.5
           
          */

          public class MethodProperty implements Property, Property.ValueChangeNotifier,
                  Property.ReadOnlyStatusChangeNotifier {

               
          //帶有getter/setter的那個 instance
              private transient Object instance;

               
          // getter 和 setter 的參數隊列

              
          private transient Object[] setArgs, getArgs;
              
          private boolean readOnly;

              
          // getter / setter methods
              private transient Method setMethod, getMethod;

              
          // 如果 setter 方法有多個參數,這個是值參數的 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 {}
              };

              
          /** 
               * 自動初始化方法,應該是供正常使用的。
               * 用這種方法建立 MethodProperty,getter 沒有參數,setter 只有一個值參數,(最基本形式)
               * 如果沒有 setter,則 property 只讀。
               
          */
              
          public MethodProperty(Object instance, String beanPropertyName) {

                  
          final Class beanClass = instance.getClass();
                  
          // 這里 beanPropertyName 因該是首字母大寫,沒有 get/set/is 之類的。如果首字母沒有大寫,本方法會修正。
                  
          // 嘗試各個方式找到 getter。
                  
          // 通過 getter 的返回類型得到 type
                  
          // 嘗試各個方式找到 setter
                  
          // 如果 type 是基本類型,轉成對應的類
                  
          // 設置調用參數,readonly, instance
              }

              
          /** 只是一些簡化版初始化方法 */
              
          public MethodProperty(Class type, Object instance, String getMethodName,
                      String setMethodName) {
              }

              
          public MethodProperty(Class type, Object instance, Method getMethod,
                      Method setMethod) {
              }

              
          /**
               * 初始化,提供全部內部屬性。平時應該不會用到。
               
          */
              
          public MethodProperty(Class type, Object instance, String getMethodName,
                      String setMethodName, Object[] getArgs, Object[] setArgs,
                      
          int setArgumentIndex) {

                  
          // 一些參數正確檢查
                  
          // 設置類型
                  
          // 從 instance.getClass().getMethods 中,根據名字,返回類型,參數個數,各個參數的類型,找到 getter。
                  
          // 總之,getter 可以不是最常見的無參數 getter,可以是任何 method。從這點上說,MethodProperty 這個名字
                  
          // 是很貼切的。
                  
          // 再找 setter,同樣過程。
                  
          // 再處理 primitive 類型
                  
          // 最后設置 arguments, readOnly, instance
              }

              
          /** 另一個版本的初始化,處理相同。
               
          */
              
          public MethodProperty(Class type, Object instance, Method getMethod,
                      Method setMethod, Object[] getArgs, Object[] setArgs,
                      
          int setArgumentIndex) {
              }

              
          // 就是簡單的 getter
              public final Class getType() {
                  
          return type;
              }
              
          public boolean isReadOnly() {
                  
          return readOnly;
              }
              
              
          // 調用,直接去從 instance 得到值。這里面沒有緩沖。    
              public Object getValue() {
                  
          try {
                      
          return getMethod.invoke(instance, getArgs);
                  } 
          catch (final Throwable e) {
                      
          throw new MethodProperty.MethodException(e);
                  }
              }

              
          // 見簡版實現
              public String toString() {
                  
          // 簡而言之: getValue().toString();
              }

              
          /** 設置 getter / setter 的參數隊列
               
          */
              
          public void setArguments(Object[] getArgs, Object[] setArgs,
                      
          int setArgumentIndex) {
                  
          // 就是拷貝出來。這樣就不會被別人修改。
              }

              
          /**
               * 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,拋出異常。

                 
          // 下面試圖直接通過 invokeSetMethod 進行設置。判斷的條件是 isAssignableFrom,也就是同類,接口實現,父類,或者
                  
          // 等同的 primitive / 類,等等,總之就是可以直接賦值。這里 type 是在初始化的時候計算的 getMethod 的返回值,并且保證
                  // 對應的 setMethod 也接受這個類型的值。
                  if (newValue == null || type.isAssignableFrom(newValue.getClass())) {
                      invokeSetMethod(newValue);
                  } 
          else {
                  
                  
          // 否則,看看該被 set 的類型有沒有一個只有一個 string 作為參數的初始化函數,如果有,就用 newValue.toString() 來初始化。這個
                  
          // 可是有些主觀啊。這樣看起來恐怕 vaadin 并沒有提供一個類型轉換框架。
                      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);
                      }

                      
          // 總之調用 setter
                      invokeSetMethod(value);
                  }
                  
          // 通知各個 listener
                  fireValueChange();
              }

              
          /**調用 setter  */
              
          private void invokeSetMethod(Object value) {
                  
          // 調用 setter,不管是只有一個參數還是多個參數。
              }

              
          // 設置只讀狀態。但是否可以不只讀還要看有沒有setter
              public void setReadOnly(boolean newStatus) {
              }

              
          /** 調用 getter / setter 時候拋出的異常,再包裝一下。 
               
          */
              
          public class MethodException extends RuntimeException {
              }

              
          /* 只讀狀態改變事件
               
          */
              
          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) {
              }
              
          // 這里說一句,valueChange事件是可以主動去 fire 的。
              public void fireValueChange() {
              }

          }



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

          主站蜘蛛池模板: 杭州市| 合江县| 准格尔旗| 锡林浩特市| 张家界市| 玛纳斯县| 山丹县| 东兰县| 通道| 浦东新区| 儋州市| 库尔勒市| 塔河县| 云和县| 中牟县| 玛曲县| 永登县| 景宁| 麟游县| 北碚区| 新兴县| 皋兰县| 绿春县| 宁远县| 石城县| 军事| 平江县| 呼伦贝尔市| 鄂托克前旗| 榆社县| 吐鲁番市| 噶尔县| 安义县| 定边县| 勃利县| 新田县| 八宿县| 浮山县| 彭泽县| 中山市| 屏边|