From aa572299d6786b8f82b3301dd5080e2bd82ecb51 Mon Sep 17 00:00:00 2001 From: huifer Date: Thu, 26 Dec 2019 09:28:30 +0800 Subject: [PATCH] mybatis objectWrapper --- .../核心处理层/Mybatis-ObjectWrapper.md | 677 ++++++++++++++++++ images/mybatis/image-20191223100956713.png | Bin 0 -> 19290 bytes 2 files changed, 677 insertions(+) create mode 100644 docs/Mybatis/核心处理层/Mybatis-ObjectWrapper.md create mode 100644 images/mybatis/image-20191223100956713.png diff --git a/docs/Mybatis/核心处理层/Mybatis-ObjectWrapper.md b/docs/Mybatis/核心处理层/Mybatis-ObjectWrapper.md new file mode 100644 index 0000000..511d6c6 --- /dev/null +++ b/docs/Mybatis/核心处理层/Mybatis-ObjectWrapper.md @@ -0,0 +1,677 @@ +# Mybatis ObjectWrapper +- Author: [HuiFer](https://github.com/huifer) +- 源码位于: `org.apache.ibatis.reflection.wrapper.ObjectWrapper`‘ + +类图: + +![image-20191223100956713](/images/mybatis/image-20191223100956713.png) +```java +public interface ObjectWrapper { + + /** + * 根据 prop 获取属性值 + * + * @param prop + * @return + */ + Object get(PropertyTokenizer prop); + + /** + * 设置属性 + * + * @param prop 属性值名称 + * @param value 属性值 + */ + void set(PropertyTokenizer prop, Object value); + + /** + * 获取属性 + * + * @param name + * @param useCamelCaseMapping + * @return + */ + String findProperty(String name, boolean useCamelCaseMapping); + + /** + * get 方法名,可读方法名 + * + * @return + */ + String[] getGetterNames(); + + /** + * set 方法名,可写方法名 + * + * @return + */ + String[] getSetterNames(); + + /** + * set 数据类型, 获取可写的数据类型 + * + * @param name + * @return + */ + Class getSetterType(String name); + + /** + * get 数据类型, 获取可读的数据类型 + * + * @param name + * @return + */ + Class getGetterType(String name); + + /** + * 判断是否包含set方法 + * + * @param name + * @return + */ + boolean hasSetter(String name); + + /** + * 判断是否包含get方法 + * + * @param name + * @return + */ + boolean hasGetter(String name); + + /** + * 初始化数据 + * + * @param name + * @param prop + * @param objectFactory + * @return + */ + MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory); + + /** + * 判断是不是 list + * + * @return + */ + boolean isCollection(); + + /** + * list add + * + * @param element + */ + void add(Object element); + + /** + * list addAll + * + * @param element + * @param + */ + void addAll(List element); + +} +``` +## BaseWrapper +```java +/** + * @author Clinton Begin + */ +public abstract class BaseWrapper implements ObjectWrapper { + + protected static final Object[] NO_ARGUMENTS = new Object[0]; + protected final MetaObject metaObject; + + protected BaseWrapper(MetaObject metaObject) { + this.metaObject = metaObject; + } + + /** + * 处理集合对象 + * @param prop + * @param object + * @return + */ + protected Object resolveCollection(PropertyTokenizer prop, Object object) { + if ("".equals(prop.getName())) { + return object; + } else { + return metaObject.getValue(prop.getName()); + } + } + + /** + * 对象获取,根据index + * map.get(index) + * 数组 array[index] + * list list.get(index) + * @param prop + * @param collection + * @return + */ + protected Object getCollectionValue(PropertyTokenizer prop, Object collection) { + if (collection instanceof Map) { + // 如果是Map类型,则index为key + return ((Map) collection).get(prop.getIndex()); + } else { + // index 作为下标直接获取 + 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."); + } + } + } + + /** + * 设置属性值 ,List , object[] , char[] boolean byte double float int long short + * map -> put(index,value) + * list -> list.set(index,value) + * array -> array[index] = value + * @param prop + * @param collection + * @param value + */ + protected void setCollectionValue(PropertyTokenizer prop, Object collection, Object value) { + if (collection instanceof Map) { + // map -> index:value + ((Map) collection).put(prop.getIndex(), value); + } else { + // 数组 -> array[index]=value + 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 +```java +public class BeanWrapper extends BaseWrapper { + + private final Object object; + + private final MetaClass metaClass; + + /** + * 构造 + * @param metaObject + * @param object + */ + public BeanWrapper(MetaObject metaObject, Object object) { + super(metaObject); + this.object = object; + this.metaClass = MetaClass.forClass(object.getClass(), metaObject.getReflectorFactory()); + } + + @Override + public Object get(PropertyTokenizer prop) { + // 索引不为空 + if (prop.getIndex() != null) { + // 实例化集合对象 + Object collection = resolveCollection(prop, object); + return getCollectionValue(prop, collection); + } else { + // 没有索引 + return getBeanProperty(prop, object); + } + } + + @Override + public void set(PropertyTokenizer prop, Object value) { + // 是否存在索引 + if (prop.getIndex() != null) { + Object collection = resolveCollection(prop, object); + // 向上层调用 BaseWrapper + setCollectionValue(prop, collection, value); + } else { + // 本类方法 + setBeanProperty(prop, object, value); + } + } + + @Override + public String findProperty(String name, boolean useCamelCaseMapping) { + return metaClass.findProperty(name, useCamelCaseMapping); + } + + @Override + public String[] getGetterNames() { + return metaClass.getGetterNames(); + } + + @Override + public String[] getSetterNames() { + return metaClass.getSetterNames(); + } + + @Override + public Class getSetterType(String name) { + PropertyTokenizer prop = new PropertyTokenizer(name); + if (prop.hasNext()) { + + MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName()); + // 是否null + if (metaValue == SystemMetaObject.NULL_META_OBJECT) { + return metaClass.getSetterType(name); + } else { + return metaValue.getSetterType(prop.getChildren()); + } + } else { + return metaClass.getSetterType(name); + } + } + + @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); + } + } + + @Override + public boolean hasSetter(String name) { + PropertyTokenizer prop = new PropertyTokenizer(name); + if (prop.hasNext()) { + 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); + } + } + + /** + * 是否包含 name 的get 方法 + * @param name + * @return + */ + @Override + public boolean hasGetter(String name) { + PropertyTokenizer prop = new PropertyTokenizer(name); + if (prop.hasNext()) { + if (metaClass.hasGetter(prop.getIndexedName())) { + MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName()); + if (metaValue == SystemMetaObject.NULL_META_OBJECT) { + return metaClass.hasGetter(name); + } else { + return metaValue.hasGetter(prop.getChildren()); + } + } else { + return false; + } + } else { + return metaClass.hasGetter(name); + } + } + + /** + * 数据嵌套处理 a.b.c 需要处理成 a->b->c + * @param name + * @param prop + * @param objectFactory + * @return + */ + @Override + public MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) { + MetaObject metaValue; + Class type = getSetterType(prop.getName()); + try { + Object newObject = objectFactory.create(type); + // 出现嵌套处理 instantiatePropertyValue->set + 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; + } + + /** + * 获取 object 的 prop 属性值 + * @param prop + * @param object + * @return + */ + private Object getBeanProperty(PropertyTokenizer prop, Object object) { + try { + // 获取get 方法 + Invoker method = metaClass.getGetInvoker(prop.getName()); + try { + // 获取属性值 + 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); + } + } + + /** + * 设置 object 的属性 prop 值为 value + * @param prop + * @param object + * @param value + */ + private void setBeanProperty(PropertyTokenizer prop, Object object, Object value) { + try { + // 获取set 方法 + Invoker method = metaClass.getSetInvoker(prop.getName()); + Object[] params = {value}; + try { + // 设置属性 + 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); + } + } + + @Override + public boolean isCollection() { + return false; + } + + @Override + public void add(Object element) { + throw new UnsupportedOperationException(); + } + + @Override + public void addAll(List list) { + throw new UnsupportedOperationException(); + } + +} +``` +## MapWrapper +```java +public class MapWrapper extends BaseWrapper { + + private final Map map; + + public MapWrapper(MetaObject metaObject, Map map) { + super(metaObject); + this.map = map; + } + + @Override + public Object get(PropertyTokenizer prop) { + // 是否有索引 + if (prop.getIndex() != null) { + Object collection = resolveCollection(prop, map); + // 嗲用 BaseWrapper + return getCollectionValue(prop, collection); + } else { + // 获取 + return map.get(prop.getName()); + } + } + + @Override + public void set(PropertyTokenizer prop, Object value) { + if (prop.getIndex() != null) { + Object collection = resolveCollection(prop, map); + setCollectionValue(prop, collection, value); + } else { + map.put(prop.getName(), value); + } + } + + @Override + public String findProperty(String name, boolean useCamelCaseMapping) { + return name; + } + + @Override + public String[] getGetterNames() { + return map.keySet().toArray(new String[map.keySet().size()]); + } + + @Override + public String[] getSetterNames() { + return map.keySet().toArray(new String[map.keySet().size()]); + } + + @Override + public Class getSetterType(String name) { + PropertyTokenizer prop = new PropertyTokenizer(name); + if (prop.hasNext()) { + MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName()); + if (metaValue == SystemMetaObject.NULL_META_OBJECT) { + return Object.class; + } else { + return metaValue.getSetterType(prop.getChildren()); + } + } else { + if (map.get(name) != null) { + return map.get(name).getClass(); + } else { + return Object.class; + } + } + } + + @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 Object.class; + } else { + return metaValue.getGetterType(prop.getChildren()); + } + } else { + if (map.get(name) != null) { + return map.get(name).getClass(); + } else { + return Object.class; + } + } + } + + @Override + public boolean hasSetter(String name) { + return true; + } + + @Override + public boolean hasGetter(String name) { + PropertyTokenizer prop = new PropertyTokenizer(name); + if (prop.hasNext()) { + if (map.containsKey(prop.getIndexedName())) { + MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName()); + if (metaValue == SystemMetaObject.NULL_META_OBJECT) { + return true; + } else { + return metaValue.hasGetter(prop.getChildren()); + } + } else { + return false; + } + } else { + return map.containsKey(prop.getName()); + } + } + + @Override + public MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) { + HashMap map = new HashMap<>(); + set(prop, map); + return MetaObject.forObject(map, metaObject.getObjectFactory(), metaObject.getObjectWrapperFactory(), metaObject.getReflectorFactory()); + } + + @Override + public boolean isCollection() { + return false; + } + + @Override + public void add(Object element) { + throw new UnsupportedOperationException(); + } + + @Override + public void addAll(List element) { + throw new UnsupportedOperationException(); + } + +} +``` +## CollectionWrapper +```java +public class CollectionWrapper implements ObjectWrapper { + + private final Collection object; + + public CollectionWrapper(MetaObject metaObject, Collection object) { + this.object = object; + } + + @Override + public Object get(PropertyTokenizer prop) { + throw new UnsupportedOperationException(); + } + + @Override + public void set(PropertyTokenizer prop, Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public String findProperty(String name, boolean useCamelCaseMapping) { + throw new UnsupportedOperationException(); + } + + @Override + public String[] getGetterNames() { + throw new UnsupportedOperationException(); + } + + @Override + public String[] getSetterNames() { + throw new UnsupportedOperationException(); + } + + @Override + public Class getSetterType(String name) { + throw new UnsupportedOperationException(); + } + + @Override + public Class getGetterType(String name) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean hasSetter(String name) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean hasGetter(String name) { + throw new UnsupportedOperationException(); + } + + @Override + public MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) { + throw new UnsupportedOperationException(); + } + + /** + * 是否是list + * + * @return true + */ + @Override + public boolean isCollection() { + return true; + } + + /** + * java {@link Collection#add(Object)} + * + * @param element + */ + @Override + public void add(Object element) { + object.add(element); + } + + /** + * java {@link Collection#addAll(Collection)} + * + * @param element + * @param + */ + @Override + public void addAll(List element) { + object.addAll(element); + } + +} +``` \ No newline at end of file diff --git a/images/mybatis/image-20191223100956713.png b/images/mybatis/image-20191223100956713.png new file mode 100644 index 0000000000000000000000000000000000000000..d470d863a72fd4f019130eb6a2b10171c9f00752 GIT binary patch literal 19290 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 literal 0 HcmV?d00001