Apache BeanUtils 拷貝屬性的實現


先說坑:

  1. 對於裝箱的Boolean類型,不能用isABCsetABC的組合,只能用getABCsetABC的組合(對於任何非基本類型,都是這樣)
  2. beanUtils的BeanUtils.copyProperties看的不是成員,而是getset方法,也就是屬性(property),對於基本boolean是看isset

 

本文環境:

java version "1.8.0"
Java(TM) SE Runtime Environment (build 1.8.0-b132)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b70, mixed mode) 

commons-beanutils 1.9.2

實現:

通過class獲取BeanInfobeanInfo = Introspector.getBeanInfo(icontext.getTargetClass()); 

具體代碼在 org.apache.commons.beanutils.DefaultBeanIntrospector.introspect(IntrospectionContext icontext) line 88 

BeanInfo中描述了很多屬性如:

對於方法的描述在methods中,對於屬性(Property)的描述在PropertiesDescripter中。

最終copy的時候是通過反射調用readMethodNamewriteMethodName來進行的復制,在復制之前還會進行類型的檢查。

 

注意:

對於屬性的獲取是通過javaIntrospector來獲取的並不是直接反射的私有成員變量。Introspector這個類Eclipsedebug的時候無法追蹤臨時變量,原因未知

如果對於裝箱的Boolean類型使用isset,會出現如下情況:

 

readMethodName是一個null…

 

看下Introspector類往下走,獲取類的Properties的源碼如下(在Introspector.getTargetPropertyInfo方法里,line : 507):

try {

    if (argCount == 0) {

        if (name.startsWith(GET_PREFIX)) {

            // Simple getter

            pd = new PropertyDescriptor(this.beanClass, name.substring(3), method, null);

        } else if (resultType == boolean.class && name.startsWith(IS_PREFIX)) {

            //上面的這個是小寫的boolean.class 並不是Boolean.class,指的是基本類型的那個boolean

            // Boolean getter

            pd = new PropertyDescriptor(this.beanClass, name.substring(2), method, null);

        }

    } else if (argCount == 1) {

        if (int.class.equals(argTypes[0]) && name.startsWith(GET_PREFIX)) {

            pd = new IndexedPropertyDescriptor(this.beanClass, name.substring(3), null, null, method, null);

        } else if (void.class.equals(resultType) && name.startsWith(SET_PREFIX)) {

            // Simple setter

            pd = new PropertyDescriptor(this.beanClass, name.substring(3), null, method);

            if (throwsException(method, PropertyVetoException.class)) {

                pd.setConstrained(true);

            }

        }

    } else if (argCount == 2) {

        if (void.class.equals(resultType) && int.class.equals(argTypes[0]) && name.startsWith(SET_PREFIX)) {

            pd = new IndexedPropertyDescriptor(this.beanClass, name.substring(3), null, null, null, method);

            if (throwsException(method, PropertyVetoException.class)) {

                pd.setConstrained(true);

            }

        }

    }

} catch (IntrospectionException ex) {

    // This happens if a PropertyDescriptor or IndexedPropertyDescriptor

    // constructor fins that the method violates details of the deisgn

    // pattern, e.g. by having an empty name, or a getter returning

    // void , or whatever.

    pd = null;

}

}

  

原理還是根據setget/isset去割字符串然后拼接property

java對於java bean的規范可以在這里下載:

 

其中關於Property有如下說明:

 

7 Properties

Properties are discrete, named attributes of a Java Bean that can affect its appearance or its behaviour.

Properties show up in a number of ways:

1. Properties may be exposed in scripting environments as though they were fields of

objects. So in a Javascript environment I might do “b.Label = foo” to set the value of a

property.

2. Properties can be accessed programmatically by other components calling their getter

and setter methods (see Section 7.1 below).

3. As part of the process of customizing a component (see Section 9), its properties may

be presented in a property sheet for a user to edit.

4. Typically a bean’s properties will be persistent, so that their state will be stored away

as part of the persistent state of the bean.

Properties can have arbitrary types, including both built-in Java types such as “int” and class

or interfaces types such as “java.awt.Color”.

 

7.1 Accessor methods

Properties are always accessed via method calls on their owning object. For readable properties

there will be a getter method to read the property value. For writable properties there will be a

setter method to allow the property value to be updated. Thus even when a script writer types

in something such as “b.Label = foo” there is still a method call into the target object to set the

property, and the target object has full programmatic control.

So properties need not just be simple data fields, they can actually be computed values. Updates

may have various programmatic side effects. For example, changing a bean’s background color

property might also cause the bean to be repainted with the new color.

For simple properties the accessor type signatures are:

void setFoo(PropertyType value); // simple setter

PropertyType getFoo(); // simple getter

GetFoo and setFoo are simply example names. Accessor methods can have arbitrary names.

However for standard naming conventions for accessor methods see the design patterns described

in Section 8.3.

 

 

8.3 Design Patterns for Properties

8.3.1 Simple properties

By default, we use design patterns to locate properties by looking for methods of the form:

public <PropertyType> get<PropertyName>();

public void set<PropertyName>(<PropertyType> a);

If we discover a matching pair of “get<PropertyName>” and “set<PropertyName>” methods

that take and return the same type, then we regard these methods as defining a read-write property

whose name will be “<propertyName>”. We will use the “get<PropertyName>” method

to get the property value and the “set<PropertyName>” method to set the property value. The

pair of methods may be located either in the same class or one may be in a base class and the

other may be in a derived class.

If we find only one of these methods, then we regard it as defining either a read-only or a writeonly

property called “<propertyName>”

By default we assume that properties are neither bound nor constrained (see Section 7).

So a simple read-write property “foo” might be represented by a pair of methods:

public Wombat getFoo();

public void setFoo(Wombat w);

8.3.2 Boolean properties

In addition, for boolean properties, we allow a getter method to match the pattern:

public boolean is<PropertyName>();

This “is<PropertyName>” method may be provided instead of a “get<PropertyName>” method,

or it may be provided in addition to a “get<PropertyName>” method.

In either case, if the “is<PropertyName>” method is present for a boolean property then we will

use the “is<PropertyName>” method to read the property value.

An example boolean property might be:

public boolean isMarsupial();

public void setMarsupial(boolean m);

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM