目录
本文介绍关于 MetaObject 的说明和使用
public class Animal {
private Animal parent;
private String name;
// 省略 getter, setter
}
@Test
public void testBean(){
Animal animal = new Animal();
MetaObject metaObject = MetaObject.forObject(animal, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(), new DefaultReflectorFactory());
metaObject.setValue("name","bean");
System.out.println(animal.getName());
}
控制台输出:bean
@Test
public void testCollection(){
Animal animal = new Animal();
animal.setName("collection");
List list = new ArrayList<>();
MetaObject metaObject = MetaObject.forObject(list, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(), new DefaultReflectorFactory());
metaObject.add(animal);
System.out.println(list.get(0).getName());
}
控制台输出:collection
@Test
public void testMap(){
Animal animal = new Animal();
animal.setName("map");
Map<String,Animal> map = new HashMap<>();
MetaObject metaObject = MetaObject.forObject(map, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(), new DefaultReflectorFactory());
metaObject.setValue("deer",animal);
System.out.println(map.get("deer").getName());
}
控制台输出:map
@Test
public void testTokenizer(){
Animal animal = new Animal();
animal.setParent(new Animal());
MetaObject metaObject = MetaObject.forObject(animal, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(), new DefaultReflectorFactory());
metaObject.setValue("parent.name","tokenizer");
System.out.println(animal.getParent().getName());
}
控制台输出:tokenizer
MetaObject 内部具有5个字段,对外提供的所有方法都是基于这5个字段的。
将这5个字段的方法取一部分对外部提供服务的组合模式
// 原始对象
private final Object originalObject;
private final ObjectWrapper objectWrapper;
private final ObjectFactory objectFactory;
private final ObjectWrapperFactory objectWrapperFactory;
private final ReflectorFactory reflectorFactory;
MetaObject 的构造器是私有的,只提供 forObject 创建MetaObject对象.
当参数object为null时,返回 SystemMetaObject.NullObject.class
对象的元数据
public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
if (object == null) {
// 记录了Class 相关的getter
return SystemMetaObject.NULL_META_OBJECT;
} else {
return new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
}
}
ObjectWrapper 是一个对象包装器,提供了对Bean,Collection,Map 不同的操作方式
- BeanWrapper
提供了object.setName
,object.setAge
以及类似object.getParent().setName()
,object.getParent().getParent().setName()
的赋值方式- MapWrapper
提供了object.getName
,object.getAge
以及类似object.getParent().getName()
,object.getParent().getParent().getName()
的取值方式- CollectionWrapper
提供了 集合的add,addAll 方法, setValue,getValue hasSetter 等方法均抛出异常
在例子中,想取出集合的第一个元素怎么办?
@Test
public void testCollectionGet(){
Animal animal = new Animal();
animal.setName("collection");
List list = new ArrayList<>();
MetaObject metaObject = MetaObject.forObject(list, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(), new DefaultReflectorFactory());
metaObject.add(animal);
Animal convert = (Animal) metaObject.getValue("[0]");
System.out.println(convert.getName());
}
控制台输出
java.lang.UnsupportedOperationException
at org.apache.ibatis.reflection.wrapper.CollectionWrapper.get(CollectionWrapper.java:38)
at org.apache.ibatis.reflection.MetaObject.getValue(MetaObject.java:122)
at com.aya.MetaObjectTest.testCollection(MetaObjectTest.java:31)
...
并没有输出我们想要的 collection
分析CollectionWrapper的get方法
org.apache.ibatis.reflection.wrapper.CollectionWrapper
@Override
public Object get(PropertyTokenizer prop) {
throw new UnsupportedOperationException();
}
@Test
public void testCustomBeanWrapper(){
Animal animal = new Animal();
animal.setName("customBeanWrapper");
List list = new ArrayList<>();
MetaObject metaObject = MetaObject.forObject(list, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(), new DefaultReflectorFactory());
metaObject.add(animal);
BeanWrapper beanWrapper = new BeanWrapper(metaObject, list);
Animal convertAnimal = (Animal)beanWrapper.get(new PropertyTokenizer("[0]"));
System.out.println(convertAnimal.getName());
}
控制台输出: customBeanWrapper
CollectionWrapper 无法进行get操作,因为它重写了get并抛出了异常, MapWrapper和BeanWrapper 并没有重写get.
所以可以包装一层, 用 BeanWrapper 来访问集合的属性
元数据对象(MetaObject)实际上就是提供 类|集合|Map
的一种自动识别的访问形式.
PropertyTokenizer 是mybatis的属性分词器
提供了对象和集合的一种概念形式, 只是记录了属性有没有子属性
例如: object.parent.name
只是记录了 object 而已,可以通过next方法创建一个对象,返回new PropertyTokenizer(“parent”)
再次调用next 返回new PropertyTokenizer(“name”)