一灸蟆、簡(jiǎn)介
??ObjectWrapper
接口是對(duì)對(duì)象的包裝隆敢,抽象了對(duì)象的屬性信息发皿,它定義了一系列查詢對(duì)象屬性信息、以及更新屬性的方法拂蝎,其類圖如下:
二穴墅、接口定義
public interface ObjectWrapper {
// 根據(jù)表達(dá)式對(duì)應(yīng)的 PropertyTokenizer 對(duì)象,讀寫(xiě)對(duì)應(yīng)的屬性
// 如果封裝的是集合類温自,則獲取指定/讀取key或下標(biāo)的value值
Object get(PropertyTokenizer prop);
void set(PropertyTokenizer prop, Object value);
// 查找屬性表達(dá)式指定的屬性玄货,第二個(gè)參數(shù)表示是否忽略屬性表達(dá)式中的下劃線
String findProperty(String name, boolean useCamelCaseMapping);
// 獲取可讀/寫(xiě)屬性集合
String[] getGetterNames();
String[] getSetterNames();
// 解析屬性表達(dá)式指定屬性的 setter/getter 方法的參數(shù)類型
Class<?> getSetterType(String name);
Class<?> getGetterType(String name);
// 判斷屬性表達(dá)式指定屬性是否有 getter/setter 方法
boolean hasSetter(String name);
boolean hasGetter(String name);
// 為屬性表達(dá)式指定的屬性創(chuàng)建響應(yīng)的 MetaObject 對(duì)象
MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory);
boolean isCollection(); // 封裝的對(duì)象是否為 Collection 類型
void add(Object element); // 調(diào)用 Collection 中的 add() 方法
<E> void addAll(List<E> element); // 調(diào)用 Collection 中的 addAll() 方法
}
三、BaseWrapper
??BaseWrapper
是實(shí)現(xiàn) ObjectWrapper 接口的抽象子類悼泌,主要為子類 BeanWrapper 和 MapWrapper 提供屬性值的獲取和設(shè)置的功能松捉,包裝了 MetaObject 對(duì)象,關(guān)于對(duì) MetaObject 的介紹馆里,詳見(jiàn):
protected static final Object[] NO_ARGUMENTS = new Object[0];
protected MetaObject metaObject;
protected BaseWrapper(MetaObject metaObject) {
this.metaObject = metaObject;
}
??BaseWrapper
對(duì)外暴露的方法解析如下隘世。
1、Object resolveCollection(PropertyTokenizer prop, Object object)
【功能】解析對(duì)象中的集合名鸠踪,調(diào)用 MetaObject 的方法獲取對(duì)應(yīng)的屬性值返回丙者。
【源碼與注解】
protected Object resolveCollection(PropertyTokenizer prop, Object object) {
// 如果表達(dá)式不合法解析不到屬性名,則直接返回默認(rèn)值
if ("".equals(prop.getName())) {
return object;
} else {
// 解析到屬性名营密,調(diào)用 MetaObject 的方法獲取屬性值返回
return metaObject.getValue(prop.getName());
}
}
2蔓钟、Object getCollectionValue(PropertyTokenizer prop, Object collection)
【功能】根據(jù)屬性表達(dá)式,獲取對(duì)應(yīng)集合中的屬性值返回卵贱,這里的集合指 Map滥沫、List、Object[] 和基本類型數(shù)組键俱。
【源碼與注解】
protected Object getCollectionValue(PropertyTokenizer prop, Object collection) {
// 如果集合是一個(gè) Map 對(duì)象兰绣,則表達(dá)式中的索引就代表 Map 中對(duì)應(yīng)的 key,eg: map['key']
if (collection instanceof Map) {
return ((Map) collection).get(prop.getIndex());
} else {
// 如果集合是一個(gè)列表或數(shù)組编振,則下標(biāo)肯定是一個(gè)整數(shù)缀辩,eg: list[0]/arr[0]
int i = Integer.parseInt(prop.getIndex());
if (collection instanceof List) {
return ((List) collection).get(i);
} else if (collection instanceof Object[]) {
return ((Object[]) collection)[i];
} else if (collection instanceof char[]) {
return ((char[]) collection)[i];
} else if (collection instanceof boolean[]) {
return ((boolean[]) collection)[i];
} else if (collection instanceof byte[]) {
return ((byte[]) collection)[i];
} else if (collection instanceof double[]) {
return ((double[]) collection)[i];
} else if (collection instanceof float[]) {
return ((float[]) collection)[i];
} else if (collection instanceof int[]) {
return ((int[]) collection)[i];
} else if (collection instanceof long[]) {
return ((long[]) collection)[i];
} else if (collection instanceof short[]) {
return ((short[]) collection)[i];
} else {
throw new ReflectionException("The '" + prop.getName() + "' property of " + collection + " is not a List or Array.");
}
}
}
3、void setCollectionValue(PropertyTokenizer prop, Object collection, Object value)
【功能】設(shè)置表達(dá)式指定的集合中某個(gè)屬性的值踪央,跟上面的方法類似臀玄。
【源碼】
protected void setCollectionValue(PropertyTokenizer prop, Object collection, Object value) {
if (collection instanceof Map) {
((Map) collection).put(prop.getIndex(), value);
} else {
int i = Integer.parseInt(prop.getIndex());
if (collection instanceof List) {
((List) collection).set(i, value);
} else if (collection instanceof Object[]) {
((Object[]) collection)[i] = value;
} else if (collection instanceof char[]) {
((char[]) collection)[i] = (Character) value;
} else if (collection instanceof boolean[]) {
((boolean[]) collection)[i] = (Boolean) value;
} else if (collection instanceof byte[]) {
((byte[]) collection)[i] = (Byte) value;
} else if (collection instanceof double[]) {
((double[]) collection)[i] = (Double) value;
} else if (collection instanceof float[]) {
((float[]) collection)[i] = (Float) value;
} else if (collection instanceof int[]) {
((int[]) collection)[i] = (Integer) value;
} else if (collection instanceof long[]) {
((long[]) collection)[i] = (Long) value;
} else if (collection instanceof short[]) {
((short[]) collection)[i] = (Short) value;
} else {
throw new ReflectionException("The '" + prop.getName() + "' property of " + collection + " is not a List or Array.");
}
}
}
四、BeanWrapper
??BeanWrapper
繼承了抽象類 BaseWrapper畅蹂,因此也繼承了父類中的 MetaObject 對(duì)象健无,并且在構(gòu)造方法中根據(jù)傳入?yún)?shù)初始化該對(duì)象,BeanWrapper 還封裝了一個(gè) JavaBean 對(duì)象及對(duì)應(yīng)的 MetaClass 對(duì)象液斜,都通過(guò)傳入?yún)?shù)初始化和創(chuàng)建累贤,源碼如下:
private Object object; // JavaBean 對(duì)象
private MetaClass metaClass; // 保存 JavaBean 對(duì)象對(duì)應(yīng)的類的元信息的 MetaClass 對(duì)象
public BeanWrapper(MetaObject metaObject, Object object) {
super(metaObject);
this.object = object;
this.metaClass = MetaClass.forClass(object.getClass(), metaObject.getReflectorFactory());
}
??BeanWrapper
實(shí)現(xiàn)了 BaseWrapper 接口中定義的所有方法叠穆,并自定義一些方法來(lái)輔助實(shí)現(xiàn),各個(gè)方法的分析如下:
1臼膏、Object get(PropertyTokenizer prop)
【功能】獲取JavaBean對(duì)象中對(duì)應(yīng)表達(dá)式的屬性的值硼被。
PS. 入?yún)?prop
代表的表達(dá)式是不帶子表達(dá)式的,即在調(diào)用 BeanWrapper 的上層代碼中渗磅,已經(jīng)完成了遞歸找到最末尾的子表達(dá)式的過(guò)程嚷硫。
【源碼與注解】
@Override
public Object get(PropertyTokenizer prop) {
// (1)如果表達(dá)式帶索引,證明這是個(gè)集合(Map始鱼、List仔掸、數(shù)組)
// 調(diào)用父類方法獲得對(duì)應(yīng)集合的對(duì)象,再根據(jù)索引獲取索引對(duì)應(yīng)的值
if (prop.getIndex() != null) {
Object collection = resolveCollection(prop, object);
return getCollectionValue(prop, collection);
} else {
// (2)表達(dá)式不帶索引风响,調(diào)用getBeanProperty方法獲取屬性值
return getBeanProperty(prop, object);
}
}
【解析】
(1)如果表達(dá)式形如:list[0]/map[key]/arr[0]
嘉汰,則先獲取對(duì)應(yīng)屬性 list/map/arr
對(duì)象的值丹禀,再獲取索引對(duì)應(yīng)的元素的值状勤。
(2)如果表達(dá)式不帶索引,則傳入的就是個(gè)屬性名双泪,調(diào)用 #getBeanProperty()
方法持搜,獲取屬性對(duì)應(yīng)的值,其源碼分析如下:
private Object getBeanProperty(PropertyTokenizer prop, Object object) {
try {
// 得到獲取屬性對(duì)應(yīng)的Invoker對(duì)象
Invoker method = metaClass.getGetInvoker(prop.getName());
try {
// 通過(guò)Invoker封裝的反射操作獲取屬性值
return method.invoke(object, NO_ARGUMENTS);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
} catch (RuntimeException e) {
throw e;
} catch (Throwable t) {
throw new ReflectionException("Could not get property '" + prop.getName() + "' from " + object.getClass() + ". Cause: " + t.toString(), t);
}
}
2焙矛、void set(PropertyTokenizer prop, Object value)
【功能】設(shè)置JavaBean對(duì)象中對(duì)應(yīng)表達(dá)式的屬性的值葫盼。
【源碼與注解】
@Override
public void set(PropertyTokenizer prop, Object value) {
if (prop.getIndex() != null) {
Object collection = resolveCollection(prop, object);
setCollectionValue(prop, collection, value);
} else {
setBeanProperty(prop, object, value);
}
}
【解析】
??跟 get
方法的實(shí)現(xiàn)類似,如果不帶索引村斟,調(diào)用 #setBeanProperty()
方法贫导,設(shè)置對(duì)應(yīng)屬性的值,其源碼如下:
private void setBeanProperty(PropertyTokenizer prop, Object object, Object value) {
try {
// 得到設(shè)置屬性對(duì)應(yīng)的Invoker對(duì)象
Invoker method = metaClass.getSetInvoker(prop.getName());
Object[] params = {value};
try {
// 通過(guò)Invoker封裝的反射操作設(shè)置屬性值
method.invoke(object, params);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
} catch (Throwable t) {
throw new ReflectionException("Could not set property '" + prop.getName() + "' of '" + object.getClass() + "' with value '" + value + "' Cause: " + t.toString(), t);
}
}
3蟆盹、Class<?> getSetterType(String name)
【功能】獲得表達(dá)式對(duì)應(yīng)的屬性的 setter 方法的參數(shù)類型孩灯。
【源碼與注解】
@Override
public Class<?> getSetterType(String name) {
PropertyTokenizer prop = new PropertyTokenizer(name); // 解析表達(dá)式
// 存在子表達(dá)式
if (prop.hasNext()) {
// 創(chuàng)建 MetaObject 對(duì)象
MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
// 如果 metaValue 為 SystemMetaObject.NULL_META_OBJECT,表示封裝的Java對(duì)象值為NULL
if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
// 通過(guò)類元信息逾滥,獲取 setter 方法對(duì)應(yīng)屬性類型
return metaClass.getSetterType(name);
} else {
// 當(dāng)對(duì)象不為空時(shí)峰档,通過(guò)對(duì)象元信息,獲取 setter 方法對(duì)應(yīng)屬性類型寨昙,可以獲得更具體的類型信息
// 遞歸判斷子表達(dá)式的children讥巡,然后返回
return metaValue.getSetterType(prop.getChildren());
}
} else {
// 如果不存在子表達(dá)式,直接調(diào)用MetaClass.getSetter獲取屬性類型
// 這里之所以用 metaClass.getSetterType(name) 而不是 metaValue.getSetterType(name)
// 是因?yàn)?metaValue.getSetterType 也是依賴 objectWrapper.getSetterType舔哪,如果還是調(diào)用
// metaValue.getSetterType 會(huì)陷入無(wú)限遞歸欢顷,metaClass 才是遞歸的出口
return metaClass.getSetterType(name);
}
}
【解析】
??這里有個(gè)不太好理解的地方,為什么優(yōu)先使用 MetaObejct捉蚤,而僅當(dāng)其封裝的對(duì)象為空時(shí)吱涉,才使用 MetaClass 對(duì)象刹泄?MetaClass 封裝的是類的元信息,MetaObject 封裝的是對(duì)象的元信息怎爵,可以將類元信息看成是對(duì)象元信息的一個(gè)子集特石,所以根據(jù)類原信息得到的一些類型信息可能更加具體,舉個(gè)例子:
public class RichType {
private RichType richType;
private Map richMap = new HashMap();
// other code
}
??RichType
中的屬性 richMap鳖链,在定義時(shí)姆蘸,并沒(méi)有指定具體的類型,所以 key 和 value 都可以是任意的 Object 的子類芙委,創(chuàng)建一個(gè)對(duì)象逞敷,并往 richMap 中壓值。
RichType object = new RichType();
object.setRichType(new RichType());
object.getRichType().setRichMap(new HashMap());
object.getRichType().getRichMap().put("haha", "123");
object.getRichType().getRichMap().put("hehe", null);
??對(duì)于 object 來(lái)說(shuō)灌侣,上述代碼中壓入的兩個(gè)值對(duì)應(yīng)的表達(dá)式為 richType.richMap.haha
和richType.richMap.hehe
推捐,對(duì)第一個(gè)表達(dá)式來(lái)說(shuō),其值為 "123"
侧啼,所以其類型是 String牛柒,而第二個(gè)值或者其他沒(méi)有壓值的值,其值都是 null痊乾,其類型是 Object皮壁,測(cè)試代碼如下:
@Test
public void shouldGetSetterType() {
RichType object = new RichType();
object.setRichType(new RichType());
object.getRichType().setRichMap(new HashMap());
object.getRichType().getRichMap().put("haha", "123");
//object.getRichType().getRichMap().put("hehe", null);
MetaObject metaObject = SystemMetaObject.forObject(object);
Class<?> hahaCls = metaObject.getObjectWrapper().getSetterType("richType.richMap.haha");
Class<?> heheCls = metaObject.getObjectWrapper().getSetterType("richType.richMap.hehe");
Assert.assertEquals(String.class, hahaCls);
Assert.assertEquals(Object.class, heheCls);
}
??執(zhí)行結(jié)果:
4、Class<?> getGetterType(String name)
【功能】獲得表達(dá)式對(duì)應(yīng)的屬性的 getter 方法的返回值類型哪审。
【源碼】
??跟 #getSetterType
的處理過(guò)程類似蛾魄。
@Override
public Class<?> getGetterType(String name) {
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext()) {
MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
return metaClass.getGetterType(name);
} else {
return metaValue.getGetterType(prop.getChildren());
}
} else {
return metaClass.getGetterType(name);
}
}
5、boolean hasSetter(String name)
【功能】是否有表達(dá)式對(duì)應(yīng)的屬性的 setter 方法湿滓。
【源碼與注解】
@Override
public boolean hasSetter(String name) {
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext()) {
// 如果找不到頂層屬性的 setter滴须,證明傳入的表達(dá)式對(duì)應(yīng)的屬性不存在
if (metaClass.hasSetter(prop.getIndexedName())) {
MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
return metaClass.hasSetter(name);
} else {
return metaValue.hasSetter(prop.getChildren());
}
} else {
return false;
}
} else {
return metaClass.hasSetter(name);
}
}
【解析】
??處理流程跟 #getGetterType
還是大同小異,差別在于 #getGetterType
解析到不存在的屬性的時(shí)候會(huì)拋出異常叽奥,異常的源頭在于 Reflector.getGetterType()
扔水,如下所示:
public Class<?> getGetterType(String propertyName) {
Class<?> clazz = getTypes.get(propertyName);
if (clazz == null) {
throw new ReflectionException("There is no getter for property named '" + propertyName + "' in '" + type + "'");
}
return clazz;
}
??而本方法,會(huì)先判斷頂層是否有 setter而线,如果沒(méi)有子表達(dá)式的屬性肯定也是不存在的铭污,直接返回 false,實(shí)際上不做這一層判斷也沒(méi)事膀篮。
6嘹狞、boolean hasGetter(String name)
【功能】是否有表達(dá)式對(duì)應(yīng)的屬性的 getter 方法。
【源碼與注解】
??與 #hasSetter()
類似誓竿。
7磅网、MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory)
【功能】為表達(dá)式指定的屬性創(chuàng)建對(duì)應(yīng)的 MetaObject 對(duì)象。
【源碼與注解】
@Override
public MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) {
MetaObject metaValue;
// 得到表達(dá)式指定屬性的類型
Class<?> type = getSetterType(prop.getName());
try {
// 創(chuàng)建對(duì)應(yīng)的屬性對(duì)象
Object newObject = objectFactory.create(type);
// 創(chuàng)建屬性對(duì)應(yīng)的 MetaObject 對(duì)象
metaValue = MetaObject.forObject(newObject, metaObject.getObjectFactory(), metaObject.getObjectWrapperFactory(), metaObject.getReflectorFactory());
// 為屬性所屬對(duì)象設(shè)置對(duì)應(yīng)的屬性值
set(prop, newObject);
} catch (Exception e) {
throw new ReflectionException("Cannot set value of property '" + name + "' because '" + name + "' is null and cannot be instantiated on instance of " + type.getName() + ". Cause:" + e.toString(), e);
}
return metaValue;
}
8筷屡、其他方法
??依賴 MetaClass
的方法實(shí)現(xiàn):
- (1)
#getGetterNames()
:調(diào)用 metaClass.getGetterNames() 實(shí)現(xiàn)涧偷。 - (2)
#getSetterNames()
:調(diào)用 metaClass.getSetterNames() 實(shí)現(xiàn)簸喂。 - (3)
#String findProperty(String, boolean)
:調(diào)用 metaClass.findProperty(String, boolean) 實(shí)現(xiàn)。
??不支持集合操作方法:
@Override
public boolean isCollection() {
return false;
}
@Override
public void add(Object element) {
throw new UnsupportedOperationException();
}
@Override
public <E> void addAll(List<E> list) {
throw new UnsupportedOperationException();
}
五燎潮、MapWrapper
??MapWrapper
同樣是 BaseWrapper 的子類喻鳄,在理解 BeanWrapper 的前提下,理解 MapWrapper 不在話下确封,對(duì)于 MapWrapper 的介紹除呵,聚焦跟 BeanWrapper 的差異即可,MapWrapper 封裝了一個(gè) Map 對(duì)象爪喘,代碼如下:
private Map<String, Object> map;
public MapWrapper(MetaObject metaObject, Map<String, Object> map) {
super(metaObject);
this.map = map;
}
??獲取設(shè)置屬性值時(shí)颜曾,BeanWrapper 要先找到對(duì)應(yīng)的 Invoker 對(duì)象,再調(diào)用其 invoke() 方法秉剑,而 MapWrapper 直接調(diào)用 Map.get/set 即可泛豪,差異如下:
??獲取可讀可寫(xiě)屬性集合時(shí),MapWrapper 會(huì)獲取其鍵集合并轉(zhuǎn)化為數(shù)組侦鹏,如下:
??獲取屬性 getter诡曙、setter 遞歸處理出口時(shí),要獲取屬性對(duì)象种柑,再調(diào)用
#getClass()
獲取岗仑,如果值為空則默認(rèn)為 Obejct.class匹耕,源碼如下:??判斷是否有表達(dá)式指定屬性的 getter/setter 的實(shí)現(xiàn)中聚请,setter 是固定返回 true,getter 則是根據(jù) key 判斷 Map 中是否有對(duì)應(yīng)的 value稳其,實(shí)現(xiàn)如下:
??其他方法的實(shí)現(xiàn)與 BeanWrapper 一致驶赏。
六、CollectionWrapper
??CollectionWrapper
封裝了一個(gè)集合對(duì)象既鞠,如下:
private Collection<Object> object;
public CollectionWrapper(MetaObject metaObject, Collection<Object> object) {
this.object = object;
}
??但對(duì)接口方法的實(shí)現(xiàn)實(shí)際上都是拋出一個(gè) UnsupportedOperationException 異常煤傍,表示不支持該操作。Collection 是一個(gè)接口嘱蛋,任何實(shí)現(xiàn)了該接口的類的實(shí)例都可以看成是一個(gè) Collection 對(duì)象蚯姆,實(shí)現(xiàn)接口的形式有多種多樣,在JDK中的默認(rèn)實(shí)現(xiàn)的類圖如下:
??不同的實(shí)現(xiàn)洒敏,會(huì)導(dǎo)致集合中元素的存儲(chǔ)形式和調(diào)用方法不一致龄恋,所以很難統(tǒng)一地實(shí)現(xiàn) ObjectWrapper 接口中定義的與集合無(wú)關(guān)的方法,其他三個(gè)集合相關(guān)方法依賴集合接口的方法凶伙,實(shí)現(xiàn)如下:
@Override
public boolean isCollection() {
return true;
}
@Override
public void add(Object element) {
object.add(element);
}
@Override
public <E> void addAll(List<E> element) {
object.addAll(element);
}
七郭毕、ObjectWrapperFactory
??ObjectWrapperFactory
是創(chuàng)建 ObjectWrapper 對(duì)象的工廠接口,默認(rèn)實(shí)現(xiàn)類為 DefaultObjectWrapper
函荣,接口定義如下:
public interface ObjectWrapperFactory {
// 是否有對(duì)象對(duì)應(yīng)的包裝類
boolean hasWrapperFor(Object object);
// 創(chuàng)建對(duì)象對(duì)應(yīng)的包裝類
ObjectWrapper getWrapperFor(MetaObject metaObject, Object object);
}
??DefaultObjectWrapperFactory
是默認(rèn)接口實(shí)現(xiàn)類显押,默認(rèn)為不支持創(chuàng)建對(duì)象對(duì)應(yīng)的包裝類扳肛,實(shí)際上就是不可用,源碼如下:
public class DefaultObjectWrapperFactory implements ObjectWrapperFactory {
@Override
public boolean hasWrapperFor(Object object) {
return false;
}
@Override
public ObjectWrapper getWrapperFor(MetaObject metaObject, Object object) {
throw new ReflectionException("The DefaultObjectWrapperFactory should never be called to provide an ObjectWrapper.");
}
}
??你可以會(huì)覺(jué)得有點(diǎn)疑惑乘碑,不可用為什么還會(huì)有這樣的一個(gè)默認(rèn)實(shí)現(xiàn)挖息,實(shí)際上這時(shí)設(shè)計(jì)中一種很常見(jiàn)的做法,可以將其看成是一個(gè)接口API的一個(gè)占位兽肤,使用接口的代碼面向接口方法編程旋讹,使用者可以按需插入自定義的實(shí)現(xiàn)類,而框架層代碼不會(huì)受到影響轿衔。