Exploring Vaadin (4) 阅读 com.vaadin.data.util.MethodProperty 源代码

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

}



你可能感兴趣的:(Exploring Vaadin (4) 阅读 com.vaadin.data.util.MethodProperty 源代码)