一、简介
ObjectWrapper
接口是对对象的包装,抽象了对象的属性信息,它定义了一系列查询对象属性信息、以及更新属性的方法,其类图如下:
二、接口定义
public interface ObjectWrapper {
// 根据表达式对应的 PropertyTokenizer 对象,读写对应的属性
// 如果封装的是集合类,则获取指定/读取key或下标的value值
Object get(PropertyTokenizer prop);
void set(PropertyTokenizer prop, Object value);
// 查找属性表达式指定的属性,第二个参数表示是否忽略属性表达式中的下划线
String findProperty(String name, boolean useCamelCaseMapping);
// 获取可读/写属性集合
String[] getGetterNames();
String[] getSetterNames();
// 解析属性表达式指定属性的 setter/getter 方法的参数类型
Class<?> getSetterType(String name);
Class<?> getGetterType(String name);
// 判断属性表达式指定属性是否有 getter/setter 方法
boolean hasSetter(String name);
boolean hasGetter(String name);
// 为属性表达式指定的属性创建响应的 MetaObject 对象
MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory);
boolean isCollection(); // 封装的对象是否为 Collection 类型
void add(Object element); // 调用 Collection 中的 add() 方法
<E> void addAll(List<E> element); // 调用 Collection 中的 addAll() 方法
}
三、BaseWrapper
BaseWrapper
是实现 ObjectWrapper 接口的抽象子类,主要为子类 BeanWrapper 和 MapWrapper 提供属性值的获取和设置的功能,包装了 MetaObject 对象,关于对 MetaObject 的介绍,详见:
protected static final Object[] NO_ARGUMENTS = new Object[0];
protected MetaObject metaObject;
protected BaseWrapper(MetaObject metaObject) {
this.metaObject = metaObject;
}
BaseWrapper
对外暴露的方法解析如下。
1、Object resolveCollection(PropertyTokenizer prop, Object object)
【功能】解析对象中的集合名,调用 MetaObject 的方法获取对应的属性值返回。
【源码与注解】
protected Object resolveCollection(PropertyTokenizer prop, Object object) {
// 如果表达式不合法解析不到属性名,则直接返回默认值
if ("".equals(prop.getName())) {
return object;
} else {
// 解析到属性名,调用 MetaObject 的方法获取属性值返回
return metaObject.getValue(prop.getName());
}
}
2、Object getCollectionValue(PropertyTokenizer prop, Object collection)
【功能】根据属性表达式,获取对应集合中的属性值返回,这里的集合指 Map、List、Object[] 和基本类型数组。
【源码与注解】
protected Object getCollectionValue(PropertyTokenizer prop, Object collection) {
// 如果集合是一个 Map 对象,则表达式中的索引就代表 Map 中对应的 key,eg: map['key']
if (collection instanceof Map) {
return ((Map) collection).get(prop.getIndex());
} else {
// 如果集合是一个列表或数组,则下标肯定是一个整数,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)
【功能】设置表达式指定的集合中某个属性的值,跟上面的方法类似。
【源码】
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 对象,并且在构造方法中根据传入参数初始化该对象,BeanWrapper 还封装了一个 JavaBean 对象及对应的 MetaClass 对象,都通过传入参数初始化和创建,源码如下:
private Object object; // JavaBean 对象
private MetaClass metaClass; // 保存 JavaBean 对象对应的类的元信息的 MetaClass 对象
public BeanWrapper(MetaObject metaObject, Object object) {
super(metaObject);
this.object = object;
this.metaClass = MetaClass.forClass(object.getClass(), metaObject.getReflectorFactory());
}
BeanWrapper
实现了 BaseWrapper 接口中定义的所有方法,并自定义一些方法来辅助实现,各个方法的分析如下:
1、Object get(PropertyTokenizer prop)
【功能】获取JavaBean对象中对应表达式的属性的值。
PS. 入参 prop
代表的表达式是不带子表达式的,即在调用 BeanWrapper 的上层代码中,已经完成了递归找到最末尾的子表达式的过程。
【源码与注解】
@Override
public Object get(PropertyTokenizer prop) {
// (1)如果表达式带索引,证明这是个集合(Map、List、数组)
// 调用父类方法获得对应集合的对象,再根据索引获取索引对应的值
if (prop.getIndex() != null) {
Object collection = resolveCollection(prop, object);
return getCollectionValue(prop, collection);
} else {
// (2)表达式不带索引,调用getBeanProperty方法获取属性值
return getBeanProperty(prop, object);
}
}
【解析】
(1)如果表达式形如:list[0]/map[key]/arr[0]
,则先获取对应属性 list/map/arr
对象的值,再获取索引对应的元素的值。
(2)如果表达式不带索引,则传入的就是个属性名,调用 #getBeanProperty()
方法,获取属性对应的值,其源码分析如下:
private Object getBeanProperty(PropertyTokenizer prop, Object object) {
try {
// 得到获取属性对应的Invoker对象
Invoker method = metaClass.getGetInvoker(prop.getName());
try {
// 通过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)
【功能】设置JavaBean对象中对应表达式的属性的值。
【源码与注解】
@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
方法的实现类似,如果不带索引,调用 #setBeanProperty()
方法,设置对应属性的值,其源码如下:
private void setBeanProperty(PropertyTokenizer prop, Object object, Object value) {
try {
// 得到设置属性对应的Invoker对象
Invoker method = metaClass.getSetInvoker(prop.getName());
Object[] params = {value};
try {
// 通过Invoker封装的反射操作设置属性值
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)
【功能】获得表达式对应的属性的 setter 方法的参数类型。
【源码与注解】
@Override
public Class<?> getSetterType(String name) {
PropertyTokenizer prop = new PropertyTokenizer(name); // 解析表达式
// 存在子表达式
if (prop.hasNext()) {
// 创建 MetaObject 对象
MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
// 如果 metaValue 为 SystemMetaObject.NULL_META_OBJECT,表示封装的Java对象值为NULL
if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
// 通过类元信息,获取 setter 方法对应属性类型
return metaClass.getSetterType(name);
} else {
// 当对象不为空时,通过对象元信息,获取 setter 方法对应属性类型,可以获得更具体的类型信息
// 递归判断子表达式的children,然后返回
return metaValue.getSetterType(prop.getChildren());
}
} else {
// 如果不存在子表达式,直接调用MetaClass.getSetter获取属性类型
// 这里之所以用 metaClass.getSetterType(name) 而不是 metaValue.getSetterType(name)
// 是因为 metaValue.getSetterType 也是依赖 objectWrapper.getSetterType,如果还是调用
// metaValue.getSetterType 会陷入无限递归,metaClass 才是递归的出口
return metaClass.getSetterType(name);
}
}
【解析】
这里有个不太好理解的地方,为什么优先使用 MetaObejct,而仅当其封装的对象为空时,才使用 MetaClass 对象?MetaClass 封装的是类的元信息,MetaObject 封装的是对象的元信息,可以将类元信息看成是对象元信息的一个子集,所以根据类原信息得到的一些类型信息可能更加具体,举个例子:
public class RichType {
private RichType richType;
private Map richMap = new HashMap();
// other code
}
RichType
中的属性 richMap,在定义时,并没有指定具体的类型,所以 key 和 value 都可以是任意的 Object 的子类,创建一个对象,并往 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);
对于 object 来说,上述代码中压入的两个值对应的表达式为 richType.richMap.haha
和richType.richMap.hehe
,对第一个表达式来说,其值为 "123"
,所以其类型是 String,而第二个值或者其他没有压值的值,其值都是 null,其类型是 Object,测试代码如下:
@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);
}
执行结果:
4、Class<?> getGetterType(String name)
【功能】获得表达式对应的属性的 getter 方法的返回值类型。
【源码】
跟 #getSetterType
的处理过程类似。
@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)
【功能】是否有表达式对应的属性的 setter 方法。
【源码与注解】
@Override
public boolean hasSetter(String name) {
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext()) {
// 如果找不到顶层属性的 setter,证明传入的表达式对应的属性不存在
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
解析到不存在的属性的时候会抛出异常,异常的源头在于 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;
}
而本方法,会先判断顶层是否有 setter,如果没有子表达式的属性肯定也是不存在的,直接返回 false,实际上不做这一层判断也没事。
6、boolean hasGetter(String name)
【功能】是否有表达式对应的属性的 getter 方法。
【源码与注解】
与 #hasSetter()
类似。
7、MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory)
【功能】为表达式指定的属性创建对应的 MetaObject 对象。
【源码与注解】
@Override
public MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) {
MetaObject metaValue;
// 得到表达式指定属性的类型
Class<?> type = getSetterType(prop.getName());
try {
// 创建对应的属性对象
Object newObject = objectFactory.create(type);
// 创建属性对应的 MetaObject 对象
metaValue = MetaObject.forObject(newObject, metaObject.getObjectFactory(), metaObject.getObjectWrapperFactory(), metaObject.getReflectorFactory());
// 为属性所属对象设置对应的属性值
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
的方法实现:
- (1)
#getGetterNames()
:调用 metaClass.getGetterNames() 实现。 - (2)
#getSetterNames()
:调用 metaClass.getSetterNames() 实现。 - (3)
#String findProperty(String, boolean)
:调用 metaClass.findProperty(String, boolean) 实现。
不支持集合操作方法:
@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 不在话下,对于 MapWrapper 的介绍,聚焦跟 BeanWrapper 的差异即可,MapWrapper 封装了一个 Map 对象,代码如下:
private Map<String, Object> map;
public MapWrapper(MetaObject metaObject, Map<String, Object> map) {
super(metaObject);
this.map = map;
}
获取设置属性值时,BeanWrapper 要先找到对应的 Invoker 对象,再调用其 invoke() 方法,而 MapWrapper 直接调用 Map.get/set 即可,差异如下:
获取可读可写属性集合时,MapWrapper 会获取其键集合并转化为数组,如下:
获取属性 getter、setter 递归处理出口时,要获取属性对象,再调用
#getClass()
获取,如果值为空则默认为 Obejct.class,源码如下:判断是否有表达式指定属性的 getter/setter 的实现中,setter 是固定返回 true,getter 则是根据 key 判断 Map 中是否有对应的 value,实现如下:
其他方法的实现与 BeanWrapper 一致。
六、CollectionWrapper
CollectionWrapper
封装了一个集合对象,如下:
private Collection<Object> object;
public CollectionWrapper(MetaObject metaObject, Collection<Object> object) {
this.object = object;
}
但对接口方法的实现实际上都是抛出一个 UnsupportedOperationException 异常,表示不支持该操作。Collection 是一个接口,任何实现了该接口的类的实例都可以看成是一个 Collection 对象,实现接口的形式有多种多样,在JDK中的默认实现的类图如下:
不同的实现,会导致集合中元素的存储形式和调用方法不一致,所以很难统一地实现 ObjectWrapper 接口中定义的与集合无关的方法,其他三个集合相关方法依赖集合接口的方法,实现如下:
@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
是创建 ObjectWrapper 对象的工厂接口,默认实现类为 DefaultObjectWrapper
,接口定义如下:
public interface ObjectWrapperFactory {
// 是否有对象对应的包装类
boolean hasWrapperFor(Object object);
// 创建对象对应的包装类
ObjectWrapper getWrapperFor(MetaObject metaObject, Object object);
}
DefaultObjectWrapperFactory
是默认接口实现类,默认为不支持创建对象对应的包装类,实际上就是不可用,源码如下:
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.");
}
}
你可以会觉得有点疑惑,不可用为什么还会有这样的一个默认实现,实际上这时设计中一种很常见的做法,可以将其看成是一个接口API的一个占位,使用接口的代码面向接口方法编程,使用者可以按需插入自定义的实现类,而框架层代码不会受到影响。