mybatis MetaObject 浅析

05/23 10:51
阅读数 69

目录

 

 

本文介绍关于 MetaObject 的说明和使用

基本使用方法

public class Animal {
    private Animal parent;
    private String name;
    // 省略 getter, setter
}

javaBean

    @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

Collection

  @Test
    public void testCollection(){
        Animal animal = new Animal();
        animal.setName("collection");
        List<Animal> 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

Map

    @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 不同的操作方式

  1. BeanWrapper
    提供了 object.setName,object.setAge 以及类似 object.getParent().setName(),object.getParent().getParent().setName() 的赋值方式
  2. MapWrapper
    提供了 object.getName,object.getAge 以及类似 object.getParent().getName(),object.getParent().getParent().getName() 的取值方式
  3. CollectionWrapper
    提供了 集合的add,addAll 方法, setValue,getValue hasSetter 等方法均抛出异常

实战

CollectionWrapper 分析

在例子中,想取出集合的第一个元素怎么办?

  @Test
    public void testCollectionGet(){
        Animal animal = new Animal();
        animal.setName("collection");
        List<Animal> 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();
  }

BeanWrapper 分析

    @Test
    public void testCustomBeanWrapper(){
        Animal animal = new Animal();
        animal.setName("customBeanWrapper");
        List<Animal> 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”)

另外,SystemMetaObject是对MetaObject的进一步易用封装,该类属于org.apache.ibatis.reflection包。使用方式见:SystemMetaObject类代码示例

展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部