commons-beanutil開源庫是apache組織的一個基礎的開源庫,爲apache中許多類提供工具方法,學習它是學習其餘開源庫實現的基礎。java
Commons-beanutil中包含大量和JavaBean操做有關的工具方法,使用它能夠輕鬆利用Java反射機制來完成代碼中所須要的功能,而不須要詳細研究反射的原理和使用,同時,該類庫中提出了動態Bean的概念,不但提供現有JavaBean的全部功能,並且還能夠在運行時動態的對Bean中的屬性數據類型進行修改以及增刪屬性。web
本文研究的是v1.7版本的commons-utils類庫。算法
轉換器用來將輸入數據轉換成須要的數據類型,同時提供統一的接口,方便客戶代碼使用和擴展。sql
Commons-beanutils包中,全部轉換器都從org.apache.commons.beanutils.Converter接口集成,添加本身須要的實現。apache
轉換器分爲如下三個部分:編程
l 數組轉換器數組
l 普通轉換器架構
l 地區敏感的轉換器app
l 轉換器工具類框架
Converter子類包含的都是轉換器的實現,通常狀況下,不須要直接實例化這些類,只須要使用ConvertUtil中convert方法,就能夠進行數據類型的轉換。高級用戶不但可使用默認的轉換方式,還能夠向ConvertUtils中註冊新的或替代原有的轉換器,實現須要的業務邏輯。
轉換器接口的詳細信息以下:
類名 |
描述 |
Converter |
BeanUtil框架中使用的類型轉換接口,能夠將輸入數據轉換成須要的類型 |
數組轉換器的實現被封裝在org.apache.commons.beanutils.converters包中。它的功能是將必定格式的輸入字符串轉換成不一樣類型的數組,輸入數據以逗號分隔,開頭和結尾能夠用大括號括起來,例如:「{1, 2, 3, 4, 5}」。
全部數組轉換器實現都從一個名爲AbstractArrayConverter的抽象基類中集成,這個類提供瞭解析輸入字符串的工具方法。
數組轉換器的詳細類說明以下:
類名 |
描述 |
AbstractArrayConverter |
用來將輸入字符串轉換成數組的抽象類,提供了全部ArrayConverter須要的公共方法。 |
BooleanArrayConverter |
將輸入的任何對象轉換成boolean數組,傳入對象要知足如下幾個條件後才能正確轉換: 1. 傳入對象爲boolean數組,直接返回。 2. 傳入對象爲String數組,只要數組中的每一個元素知足特定條件,就能夠正常解析爲boolean數組。 3. 傳入對象爲其餘類型,只要對象的toString()方法返回的字符串爲逗號分隔的格式,而且每部分知足特定條件,就能夠解析爲boolean數組。 能夠向boolean類型轉換的字符串以下: l yes,y,true,on,1被轉換爲true l no,n,false,off,被轉換成false l 其餘字符串爲非法字符串,若是遇到就中止轉換,拋出異常或返回默認值。 原有代碼實現的缺陷和改進方案: 1. 字符串數組解析算法重複:能夠經過提取公共函數的方法消除重複。 2. try/catch嵌套混亂:解決方法同上,只要提取公共方法後天然就能夠解決這個問題。 3. 特殊字符串被硬編碼,例如yes,y,no,n等:將這些特殊字串提取成常量,放入映射表中維護,減小複雜的判斷語句。 |
ByteArrayConverter |
將傳入對象轉換爲byte數組,若是轉換失敗,就拋出異常。 仍然有重複代碼的問題。 |
CharacterArrayConverter |
將對象轉換爲char數組 |
DoubleArrayConverter |
將對象轉換成double數組 |
FloatArrayConverter |
將對象轉換成float數組 |
IntegerArrayConverter |
將對象轉換成int數組 |
LongArrayConverter |
將對象轉換成long數組 |
ShortArrayConverter |
將對象轉換成short數組 |
StringArrayConverter |
javadoc中說是將String數組轉換成String數組,但不知道這樣有什麼意義。 查看代碼後發現算法只能轉換int型的數組爲String數組,其餘的類型好比long型數組均不能正常轉換。 最好不用這個類。 |
以上類構成了以下的類結構圖:
經過閱讀數組轉換器的代碼,發現代碼存在如下問題:
1. 代碼冗餘:代碼不夠簡潔,每一個類中都或多或少的存在代碼複製粘貼的痕跡。
2. 部分類的類型轉換時存在缺陷,不能正常轉換。
普通轉換器提供了將字符串轉換成Java中的數字、時間日期類型和其餘類型對象的方法。
普通轉換器都直接從Converter接口集成,實現其中的抽象方法。
用戶不但能夠直接使用這些工具方法,也能夠本身實現一些特殊業務需求的轉換器,只要實現Converter接口便可。
普通轉換器的類說明以下:
類名 |
描述 |
BigDecimalConverter |
將字符串轉換成BigDecimal類型數據。轉換失敗時能夠拋出異常,也能夠返回默認值。 |
BigIntegerConverter |
將數組轉換成java.math.BigInteger類型對象,若是轉換失敗,能夠拋出異常,也能夠直接返回默認值。 |
BooleanConverter |
將字符串轉換成boolean類型對象。 若是轉換失敗,能夠拋出異常,也能夠返回默認值。 |
ByteConverter |
將字符串轉換成byte類型,若是轉換失敗,拋出異常或返回默認值。 |
CharacterConverter |
將字符串轉換成char,若是轉換失敗,拋出異常或返回默認值。 |
ClassConverter |
從當前上下文的ClassLoader中加載類,若是類不存在,能夠拋出異常,也能夠直接返回默認值。 |
DoubleConverter |
將輸入字符串轉換成double類型。若是轉換失敗,能夠拋出異常,也能夠返回默認值。 |
FileConverter |
根據輸入字符串初始化File對象,若是對象建立失敗,拋出異常或返回默認值。 |
FloatConverter |
將字符串轉換成Float類型,若是轉換失敗,能夠拋出異常,能夠返回默認值。 |
IntegerConverter |
將字符串轉換成Integer類型對象,若是轉換失敗,能夠拋出異常,也能夠返回默認值。 |
LongConverter |
將字符串轉換成Long類型對象,若是轉換失敗,能夠拋出異常,也能夠返回默認值。 |
ShortConverter |
將字符串轉換成short類型對象,若是轉換失敗,能夠拋出異常,也能夠返回默認值。 |
SqlTimeConverter |
將字符串轉換成java.sql.Time對象,若是轉換失敗,能夠拋出異常,也能夠返回默認值。 |
SqlTimestampConverter |
將字符串轉換成javax.sql.Timestamp對象,若是轉換失敗,能夠拋出異常,也能夠返回默認值。 |
StringConverter |
將字符串對象轉換成字符串對象。 單獨使用沒有什麼意義,可是在面向接口編程中實現了一種通用的轉換方法,比較有用。 |
URLConverter |
將字符串轉換成URL對象,若是轉換失敗,拋出異常,或者直接返回默認值。 |
|
|
通用轉換器的類結構圖以下:
通用轉換器存在的問題是:
對於默認值的校驗不到位,沒有針對具體Converter的類型進行校驗,一旦轉換失敗,直接返回默認值後可能致使後續代碼出現ClassCastException,沒有從源頭杜絕這種狀況發生,雖然這樣設計更加靈活,但弊大於利,最好是在類建立時進行校驗。
地區敏感轉換器都被封裝在org.apache.commons.beanutils.locale和org.apache.commons.beanutils.locale.converters包中,前者提供一個集成自Converter的通用接口,後者提供這個接口的具體實現。
地區敏感轉換器主要實現了當須要分地區進行轉換時,須要進行的操做。主要功能是將帶有不一樣地區特徵的字符串轉換成數字和時間日期類型對象。
地區敏感轉換器的類說明以下:
類名 |
描述 |
LocaleConverter |
進行地區敏感的數據類型的轉換 |
BaseLocaleConverter |
封裝全部地區敏感conveter的公共方法 |
DateLocaleConverter |
將地區敏感對象轉換成java.util.Date對象。 |
SqlDateLocaleConverter |
將輸入對象轉換成java.sql.Date 對象 |
SqlTimeLocaleConverter |
將輸入對象轉換成java.sql.Time對象 |
SqlTimestampLocaleConverter |
將輸入對象轉換成java.sql.Timestamp的格式 |
DecimalLocaleConverter |
將地區敏感的輸入轉換成java.lang.Decimal對象 |
BigDecimalLocaleConverter |
將輸入的地區敏感字符串轉換成java.math.BigDecimal對象。 沒有重寫任何方法,應該只是爲了和其餘實現樣式一致編寫的方法。 |
BigIntegerLocaleConverter |
將輸入的地區敏感的對象轉換成java.math.BigInteger 對象 沒有重寫任何方法,應該只是爲了和其餘實現樣式一致編寫的方法。 |
ByteLocaleConverter |
將輸入的地區敏感的字符串轉換成java.lang.Byte 對象 |
DoubleLocaleConverter |
將地區敏感的對象轉換成java.lang.Double對象 |
FloatLocaleConverter |
將地區敏感的字符串轉換成java.lang.Float對象 |
IntegerLocaleConverter |
將地區敏感的字符串轉換成java.lang.Integer對象 |
LongLocaleConverter |
將地區敏感的字符串轉換成java.lang.Long對象 |
ShortLocaleConverter |
將地區敏感的字符串轉換成java.lang.Short對象 |
StringLocaleConverter |
將字符串轉換成數字的字符串形式。 好像沒有什麼實際的做用 |
地區敏感轉換器的類圖以下:
地區敏感轉換器中全部參數參數都是直接從構造函數中輸入的,沒有get和set,代碼冗餘度很大,須要重構。
轉換器相關的工具類是外界實際使用的接口,默認狀況下,系統會向工具類中註冊上述各類類型數據的轉換器對象,用戶能夠自定義這些註冊信息,添加,修改或刪除本身不須要的轉換器,還能夠將本身實現的類型註冊到轉換器中。
轉換器工具類的詳細信息以下:
類名 |
描述 |
ConvertUtils |
將字符串對象轉換成相應類型的對象。如,將String對象轉換成Integer類型的對象,或將String對象轉換成Integer數組對象。 默認使用系統自定義的轉換器,但接口開放,能夠自定義轉換器進行數據類型轉換。 |
ConvertUtilsBean |
實際進行數據轉換的類。 |
LocaleConvertUtils |
和ConvertUtils做用相似,在轉換的過程當中根據不一樣的地區進行不用的轉換,適用於地區敏感的數據。 |
LocaleConvertUtilsBean |
轉換器這一套代碼中實現了字符串向Java中各類數據類型的轉換,這樣在轉換數據類型時不須要了解各類數據類型的轉換API,只須要知道Converter接口便可,方便了開發人員編寫代碼。
但這套代碼也有不少不足,其中最大的就是代碼冗餘的問題,小到函數內部的實現,大到整個的類結構,或多或少的都存在代碼複製粘貼的影子,能夠經過重構讓代碼變得更加清晰。
咱們知道,每個JavaBean對象中包含一個Class對象,這個對象是單實例的而且在當前類加載器中全局惟一,由JVM維護,用來存儲Bean中的屬性描述信息,這些信息在運行時沒法修改。
動態bean符合JavaBean架構的基本思想,每個DynaBean實例有一個DynaClass對象,這個對象在同類DynaBean中惟一,但能夠動態的對屬性進行增刪改的操做。這樣就彌補了原來JavaBean架構中當Bean定義後不能對Bean中屬性進行擴展的缺點,同時,提供了對bean中屬性進行get/set的統一工具類,這些工具類的接口能夠兼容動態Bean、標準Bean,以及映射(map)。
動態Bean中的屬性使用DynaProperty對象進行描述,
類名 |
描述 |
DynaProperty |
動態bean中的屬性,由屬性名,屬性類型兩部分組成,對於數組、鏈表這類複雜類型,還加入了內容類型的概念,用來描述這些複雜數據接口內部對象的類型。 |
動態Bean的Class對象描述了Bean中包含的屬性以及屬性的數據類型,分爲DynaClass和MutableDynaClass兩個接口,其中MutableDynaClass接口繼承自DynaClass接口,同時提供對Bean屬性進行修改的方法。
詳細描述以下:
接口名 |
描述 |
DynaClass |
動態類模仿java.lang.Class 的實現。使用DynaClass建立DynaBean 對象,全部DynaBean 對象共享一個DynaClass實例。 |
MutableDynaClass |
對於DynaClass的特殊擴展,容許動態的添加和移除類的屬性 |
有多個類擴展了以上兩個接口,詳細信息以下:
類名 |
描述 |
BasicDynaClass |
對DynaClass接口的基本實現,提供了最基本的功能。 |
JDBCDynaClass |
實現JDBC邏輯的動態類 |
ResultSetDynaClass |
封裝java.sql.ResultSet對象,提供和其餘對象同樣訪問方式的類。 |
RowSetDynaClass |
從ResultSet中讀取全部數據,封裝在RowSetDynaBean中。 |
LazyDynaClass |
|
DynaProperty |
動態bean中的屬性 |
WrapDynaClass |
封裝標準JavaBean的動態bean的DynaClass對象 |
上述類之間的關係以下:
全部動態Bean實例都繼承自DynaBean接口,能夠建立DynaBean的實例,並對其屬性進行修改。
接口詳細信息以下:
接口名 |
描述 |
DynaBean |
提供了屬性類型,名稱,內容能夠動態修改的JavaBean。 |
如下類實現了DynaBean接口:
類名 |
描述 |
WrapDynaClass |
封裝標準JavaBean的動態bean的DynaClass對象 |
BasicDynaBean |
對DynaBean接口的最小實現 |
ResultSetIterator |
封裝ResultSetDynaClass的DynaBean |
LazyDynaBean |
能夠動態添加屬性的Bean |
WrapDynaBean |
封裝標準的JavaBean,提供DynaBean的訪問方式 |
ConvertingWrapDynaBean |
WrapDynaBean的子類,在set數據時能夠提供必要的數據類型轉換 |
DynaBean相關類之間關係以下:
和任何成熟的開源包同樣,commons-beanutils做爲一個工具包,提供了對JavaBean以及動態Bean進行操做的工具類,即便沒有使用動態Bean,仍然能夠放心的使用這些工具類。
經常使用的工具類有如下幾個部分:
l PropertyUtils:對JavaBean中的屬性值進行操做。
l MethodUtils:使用反射的方式請求bean中的方法。
l ConstructorUtils:使用反射的方式構造Bean的新實例。
l BeanUtils:對JavaBean提供拷貝,賦值等操做。
l LocaleBeanUtils:和BeanUtils功能相似,但還能夠提供地區敏感數據的操做。
l ContextClassLoaderLocal:爲不一樣線程保存須要數據的工具類。
工具類的詳細說明以下:
類名 |
描述 |
ContextClassLoaderLocal |
提供保存不一樣線程數據的工具類,在JDK1.5中已經能夠用ThreadLocal代替. |
PropertyUtils |
使用Java反射API編寫的工具類,用於方便的進行get和set。 本工具類的全部實現都是對PropertyUtilsBean的封裝和代理。 |
PropertyUtilsBean |
使用Java反射API進行set和get的工具類。 |
MethodUtils |
封裝以放射方式請求方法的工具方法 |
ConstructorUtils |
使用反射方法請求構造函數建立新實例的工具類,能夠簡化程序中使用反射方式建立對象的代碼。 |
BeanUtilsBean |
提供對標準JavaBean和動態bean的操做。主要功能是複製bean中的內容,拷貝bean,爲bean中的內容賦值和讀取bean中內容。 |
BeanUtils |
|
LocaleBeanUtils |
和BeanUtils做用相似,但在執行相應方法時能夠進行地區敏感數據的轉換。 |
LocaleBeanUtilsBean |
經過研讀commons-beanutils的源代碼,整理了PropertyUtilsBean中的相關方法,以下所示:
PropertyUtilsBean的方法名 |
描述 |
copyProperties |
bean屬性拷貝(copyProperties),能夠拷貝bean中全部屬性,拷貝時遵循原來bean中的訪問控制策略: l 動態bean向動態bean拷貝 l 動態bean向標準bean拷貝 l MAP向動態bean拷貝 l Map向標準bean拷貝 l 標準bean向動態bean拷貝 l 標準bean向標準bean拷貝 |
describe |
將bean屬性拷貝到Map中。 只拷貝源bean中可讀的屬性,忽略其餘屬性。 |
getIndexedProperty |
獲得bean中的索引屬性值: 有兩種形式,一種的參數是string,另外一種的參數是屬性名和位置,前者是「name[1]」的形式,後者是「name, 1」的形式。 例如,要取出bean中名爲name屬性的第2個對象,可使用getIndexedProperty(bean, 「name[1]」)的形式,也可使用getIndexedProperty(bean, 「name」, 1)的形式。 l 若是輸入是動態bean,能夠獲得動態bean的索引屬性。 若是屬性是數組或列表,能夠獲得相應屬性。 |
getMappedProperty |
獲得bean中的映射屬性值: 本方法有兩種原型,能夠輸入(bean, 「name(key)」)取出bean中名爲name映射屬性中以key爲鍵的屬性值;也能夠輸入(bean, 「name」, 「key」)的方式取出bean中名爲name映射屬性中以key爲鍵的屬性值。
|
getNestedProperty |
獲得bean中的嵌套屬性值。獲取值的bean須要有get方法,還要有public訪問權限,不然BeanUtils中的類沒法訪問。 適合在web頁面上進行bean值的讀取。 |
getPropertyDescriptor |
獲得bean中相應屬性的屬性描述符 |
getPropertyDescriptors |
獲得bean中全部屬性的屬性描述符 |
getPropertyEditorClass |
獲得bean中的屬性編輯器類 |
getPropertyType |
獲得bean中相應屬性類型 |
getReadMethod |
獲得屬性描述符中的get方法 |
getSimpleProperty |
獲得bean中簡單屬性的值 |
getWriteMethod |
獲得屬性描述符中的寫方法 |
isReadable |
判斷bean中的指定屬性是否可讀 |
isWriteable |
判斷bean中的對應方法是否可寫 |
setIndexedProperty |
向bean中的索引屬性賦值 |
setMappedProperty |
向bean中的映射屬性賦值 |
setNestedProperty |
向bean中的內嵌屬性賦值 |
setProperty |
爲bean中的屬性賦值(包括簡單屬性和索引屬性) |
setSimpleProperty |
爲bean中的簡單屬性賦值 |
Commons-beanutils是一款優秀的工具類庫。不但提供了一種能夠動態擴展屬性的JavaBean,同時封裝了Java的反射機制,使用者能夠更加容易的對反射進行操做,而不須要了解那麼多和反射相關的知識。