1.metaObject 是啥
MetaObject类相当于一个对象工具类,Mybatis在sql参数设置和结果集映射里经常使用到这个对象。 映射是指结果集中的列填充至JAVA Bean属性。这就必须用到反射,而Bean的属性 多种多样的有普通属性、对象、集合、Map都有可能。为了更加方便的操作Bean的属性,MyBatis提供了MeataObject 工具类,其简化了对象属性的操作。
1.1 metaObject的使用
实体类
import lombok.Data; @Data public class user { /** * 名称 */ private String name; /** * id */ private String id; }
测试
public static void main(String[] args) { //装饰器模式 user bizDict = new user(); Configuration configuration=new Configuration(); // 装饰 MetaObject metaobject = configuration.newMetaObject(bizDict); metaobject.setValue("name","babababa"); System.out.println(metaobject.getValue( "name")); }
输出
2.mybatis对metaObject 详解
2.1 全景图
2.2 mybatis 的metaObject类详细解说
/* * Copyright 2009-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.ibatis.reflection; import java.util.Collection; import java.util.List; import java.util.Map; import org.apache.ibatis.reflection.factory.ObjectFactory; import org.apache.ibatis.reflection.property.PropertyTokenizer; import org.apache.ibatis.reflection.wrapper.BeanWrapper; import org.apache.ibatis.reflection.wrapper.CollectionWrapper; import org.apache.ibatis.reflection.wrapper.MapWrapper; import org.apache.ibatis.reflection.wrapper.ObjectWrapper; import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory; /** * @author Clinton Begin */ public class MetaObject { // 原始的 Java 对象 private final Object originalObject; // 对象包装器,用于获取和设置对象的属性值 private final ObjectWrapper objectWrapper; // 对象工厂,用于创建 Java 对象 private final ObjectFactory objectFactory; // 对象包装器工厂,用于创建对象包装器 private final ObjectWrapperFactory objectWrapperFactory; // 反射器工厂,用于创建反射器 private final ReflectorFactory reflectorFactory; // 构造函数,创建 MetaObject 对象 private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) { this.originalObject = object; this.objectFactory = objectFactory; this.objectWrapperFactory = objectWrapperFactory; this.reflectorFactory = reflectorFactory; // 根据对象类型创建对应的对象包装器 if (object instanceof ObjectWrapper) { this.objectWrapper = (ObjectWrapper) object; } else if (objectWrapperFactory.hasWrapperFor(object)) { this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object); } else if (object instanceof Map) { this.objectWrapper = new MapWrapper(this, (Map) object); } else if (object instanceof Collection) { this.objectWrapper = new CollectionWrapper(this, (Collection) object); } else { this.objectWrapper = new BeanWrapper(this, object); } } // 静态工厂方法,用于创建 MetaObject 对象 public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) { if (object == null) { return SystemMetaObject.NULL_META_OBJECT; } return new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory); } // 获取对象工厂 public ObjectFactory getObjectFactory() { return objectFactory; } // 获取对象包装器工厂 public ObjectWrapperFactory getObjectWrapperFactory() { return objectWrapperFactory; } // 获取反射器工厂 public ReflectorFactory getReflectorFactory() { return reflectorFactory; } // 获取原始 Java 对象 public Object getOriginalObject() { return originalObject; } // 查找属性名,支持驼峰命名和下划线命名的转换 public String findProperty(String propName, boolean useCamelCaseMapping) { return objectWrapper.findProperty(propName, useCamelCaseMapping); } // 获取所有 getter 方法名 public String[] getGetterNames() { return objectWrapper.getGetterNames(); } // 获取所有 setter 方法名 public String[] getSetterNames() { return objectWrapper.getSetterNames(); } /** * 获取指定属性的 setter 方法的参数类型 * @param name * @return */ public Class<?> getSetterType(String name) { return objectWrapper.getSetterType(name); } /** * 获取指定属性的 getter 方法的返回值类型 * @param name * @return */ public Class<?> getGetterType(String name) { return objectWrapper.getGetterType(name); } /** * 判断指定属性是否有 setter 方法 * @param name * @return */ public boolean hasSetter(String name) { return objectWrapper.hasSetter(name); } /** * 判断指定属性是否有 getter 方法 * @param name * @return */ public boolean hasGetter(String name) { return objectWrapper.hasGetter(name); } /** * 获取指定属性的值 * @param name * @return */ public Object getValue(String name) { PropertyTokenizer prop = new PropertyTokenizer(name); if (!prop.hasNext()) { return objectWrapper.get(prop); } MetaObject metaValue = metaObjectForProperty(prop.getIndexedName()); if (metaValue == SystemMetaObject.NULL_META_OBJECT) { return null; } else { return metaValue.getValue(prop.getChildren()); } } /** * 设置指定属性的值 * @param name * @param value */ public void setValue(String name, Object value) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { MetaObject metaValue = metaObjectForProperty(prop.getIndexedName()); if (metaValue == SystemMetaObject.NULL_META_OBJECT) { if (value == null) { // 如果值为 null,则不创建子路径 return; } metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory); } metaValue.setValue(prop.getChildren(), value); } else { objectWrapper.set(prop, value); } } /** * 获取指定属性的 MetaObject 对象 * @param name * @return */ public MetaObject metaObjectForProperty(String name) { Object value = getValue(name); return MetaObject.forObject(value, objectFactory, objectWrapperFactory, reflectorFactory); } /** * 判断对象是否为集合类型 * @return */ public boolean isCollection() { return objectWrapper.isCollection(); } /** * 向集合类型对象中添加元素 * @param element */ public void add(Object element) { objectWrapper.add(element); } /** * 向集合类型对象中添加多个元素 * @param list * @param <E> */ public <E> void addAll(List<E> list) { objectWrapper.addAll(list); } }
2.3 BeanWrapper 代码详细解析
/* * Copyright 2009-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.ibatis.reflection.wrapper; import java.util.List; import org.apache.ibatis.reflection.ExceptionUtil; import org.apache.ibatis.reflection.MetaClass; import org.apache.ibatis.reflection.MetaObject; import org.apache.ibatis.reflection.ReflectionException; import org.apache.ibatis.reflection.SystemMetaObject; import org.apache.ibatis.reflection.factory.ObjectFactory; import org.apache.ibatis.reflection.invoker.Invoker; import org.apache.ibatis.reflection.property.PropertyTokenizer; /** * @author Clinton Begin */ /** * BeanWrapper 是 MyBatis 中的一个包装类,用于实现对 JavaBean 对象的包装和操作。 * 主要实现了以下功能: * 1. 获取 JavaBean 对象的属性值,包括普通属性和集合属性。 * 2. 设置 JavaBean 对象的属性值,包括普通属性和集合属性。 * 3. 查找 JavaBean 对象的属性名。 * 4. 获取 JavaBean 对象的 getter 方法名和 setter 方法名。 * 5. 获取 JavaBean 对象的 getter 方法返回值类型和 setter 方法参数类型。 * 6. 判断 JavaBean 对象是否有指定属性的 getter 方法和 setter 方法。 * 7. 实例化 JavaBean 对象的属性值。 * 8. 判断 JavaBean 对象是否为集合类型。 * 9. 向 JavaBean 对象的集合属性中添加元素。 */ public class BeanWrapper extends BaseWrapper { /** * 被包装的 JavaBean 对象 */ private final Object object; /** * JavaBean 对象的元信息类 */ private final MetaClass metaClass; /** * 构造方法,接收 MetaObject 对象和 JavaBean 对象 * @param metaObject * @param object */ public BeanWrapper(MetaObject metaObject, Object object) { // 调用父类构造方法 super(metaObject); // 初始化被包装的 JavaBean 对象 this.object = object; // 初始化 JavaBean 对象的元信息类 this.metaClass = MetaClass.forClass(object.getClass(), metaObject.getReflectorFactory()); } /** * 获取 JavaBean 对象的属性值 * @param prop * @return */ @Override public Object get(PropertyTokenizer prop) { // 如果属性是集合类型 if (prop.getIndex() != null) { // 解析集合类型属性 Object collection = resolveCollection(prop, object); // 获取集合类型属性的值 return getCollectionValue(prop, collection); } // 获取普通属性的值 return getBeanProperty(prop, object); } /** * // 设置 JavaBean 对象的属性值 * @param prop * @param value */ @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); } } /** * 查找 JavaBean 对象的属性名 * @param name * @param useCamelCaseMapping * @return */ @Override public String findProperty(String name, boolean useCamelCaseMapping) { // 调用元信息类的方法查找属性名 return metaClass.findProperty(name, useCamelCaseMapping); } /** * 获取 JavaBean 对象的 getter 方法名 * @return */ @Override public String[] getGetterNames() { // 调用元信息类的方法获取 getter 方法名 return metaClass.getGetterNames(); } /** * 获取 JavaBean 对象的 setter 方法名 * @return */ @Override public String[] getSetterNames() { // 调用元信息类的方法获取 setter 方法名 return metaClass.getSetterNames(); } /** * 获取 JavaBean 对象的 setter 方法参数类型 * @param name * @return */ @Override public Class<?> getSetterType(String name) { // 解析属性名 PropertyTokenizer prop = new PropertyTokenizer(name); if (!prop.hasNext()) { // 如果没有子属性,直接调用元信息类的方法获取参数类型 return metaClass.getSetterType(name); } // 获取子属性的元对象 MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName()); // 如果子属性为空 if (metaValue == SystemMetaObject.NULL_META_OBJECT) { // 直接调用元信息类的方法获取参数类型 return metaClass.getSetterType(name); } else { // 递归获取子属性的参数类型 return metaValue.getSetterType(prop.getChildren()); } } /** * 获取 JavaBean 对象的 getter 方法返回值类型 * @param name * @return */ @Override public Class<?> getGetterType(String name) { // 解析属性名 PropertyTokenizer prop = new PropertyTokenizer(name); if (!prop.hasNext()) { // 如果没有子属性,直接调用元信息类的方法获取返回值类型 return metaClass.getGetterType(name); } // 获取子属性的元对象 MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName()); // 如果子属性为空 if (metaValue == SystemMetaObject.NULL_META_OBJECT) { // 直接调用元信息类的方法获取返回值类型 return metaClass.getGetterType(name); } else { // 递归获取子属性的返回值类型 return metaValue.getGetterType(prop.getChildren()); } } /** * 判断 JavaBean 对象是否有指定属性的 setter 方法 * @param name * @return */ @Override public boolean hasSetter(String name) { // 解析属性名 PropertyTokenizer prop = new PropertyTokenizer(name); if (!prop.hasNext()) { // 如果没有子属性,直接调用元信息类的方法判断是否有 setter 方法 return metaClass.hasSetter(name); } // 如果有 setter 方法 if (metaClass.hasSetter(prop.getIndexedName())) { // 获取子属性的元对象 MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName()); // 如果子属性为空 if (metaValue == SystemMetaObject.NULL_META_OBJECT) { // 直接调用元信息类的方法判断是否有 setter 方法 return metaClass.hasSetter(name); } else { // 递归判断子属性是否有 setter 方法 return metaValue.hasSetter(prop.getChildren()); } } else { // 如果没有 setter 方法,返回 false return false; } } /** * 判断 JavaBean 对象是否有指定属性的 getter 方法 * @param name * @return */ @Override public boolean hasGetter(String name) { // 解析属性名 PropertyTokenizer prop = new PropertyTokenizer(name); if (!prop.hasNext()) { // 如果没有子属性,直接调用元信息类的方法判断是否有 getter 方法 return metaClass.hasGetter(name); } // 如果有 getter 方法 if (metaClass.hasGetter(prop.getIndexedName())) { // 获取子属性的元对象 MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName()); // 如果子属性为空 if (metaValue == SystemMetaObject.NULL_META_OBJECT) { // 直接调用元信息类的方法判断是否有 getter 方法 return metaClass.hasGetter(name); } else { // 递归判断子属性是否有 getter 方法 return metaValue.hasGetter(prop.getChildren()); } } else { // 如果没有 getter 方法,返回 false return false; } } /** * 实例化 JavaBean 对象的属性值 * @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); metaValue = MetaObject.forObject(newObject, metaObject.getObjectFactory(), metaObject.getObjectWrapperFactory(), // 创建新的元对象 metaObject.getReflectorFactory()); // 设置子属性的值 set(prop, newObject); } catch (Exception e) { // 抛出 ReflectionException 异常 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; } /** * 获取 JavaBean 对象的属性值 * @param prop * @param object * @return */ private Object getBeanProperty(PropertyTokenizer prop, Object object) { try { // 获取 getter 方法的 Invoker 对象 Invoker method = metaClass.getGetInvoker(prop.getName()); try { // 调用 getter 方法获取属性值 return method.invoke(object, NO_ARGUMENTS); } catch (Throwable t) { // 抛出异常 throw ExceptionUtil.unwrapThrowable(t); } } catch (RuntimeException e) { // 抛出异常 throw e; } catch (Throwable t) { throw new ReflectionException( // 抛出 ReflectionException 异常 "Could not get property '" + prop.getName() + "' from " + object.getClass() + ". Cause: " + t.toString(), t); } } /** * 设置 JavaBean 对象的属性值 * @param prop * @param object * @param value */ private void setBeanProperty(PropertyTokenizer prop, Object object, Object value) { try { // 获取 setter 方法的 Invoker 对象 Invoker method = metaClass.getSetInvoker(prop.getName()); // 设置参数数组 Object[] params = { value }; try { // 调用 setter 方法设置属性值 method.invoke(object, params); } catch (Throwable t) { // 抛出异常 throw ExceptionUtil.unwrapThrowable(t); } } catch (Throwable t) { // 抛出 ReflectionException 异常 throw new ReflectionException("Could not set property '" + prop.getName() + "' of '" + object.getClass() + "' with value '" + value + "' Cause: " + t.toString(), t); } } /** * 判断 JavaBean 对象是否为集合类型 * @return */ @Override public boolean isCollection() { // 不是集合类型,返回 false return false; } /** * 向 JavaBean 对象的集合属性中添加元素 * @param element */ @Override public void add(Object element) { // 抛出 UnsupportedOperationException 异常 throw new UnsupportedOperationException(); } /** * 向 JavaBean 对象的集合属性中添加元素 * @param list * @param <E> */ @Override public <E> void addAll(List<E> list) { // 抛出 UnsupportedOperationException 异常 throw new UnsupportedOperationException(); } }
2.4 MetaClass 代码详细解说
/* * Copyright 2009-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.ibatis.reflection; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Collection; import org.apache.ibatis.reflection.invoker.GetFieldInvoker; import org.apache.ibatis.reflection.invoker.Invoker; import org.apache.ibatis.reflection.invoker.MethodInvoker; import org.apache.ibatis.reflection.property.PropertyTokenizer; /** * @author Clinton Begin */ /** * MetaClass 类用于对 Java 类进行反射操作,可以获取类的属性、方法、构造方法等信息。 * 它是对 Reflector 类的进一步封装,提供了更加方便的 API。 */ public class MetaClass { private final ReflectorFactory reflectorFactory; // Reflector 工厂,用于创建 Reflector 对象 private final Reflector reflector; // 封装了目标类的反射信息的 Reflector 对象 private MetaClass(Class<?> type, ReflectorFactory reflectorFactory) { this.reflectorFactory = reflectorFactory; this.reflector = reflectorFactory.findForClass(type); // 根据目标类创建 Reflector 对象 } /** * 根据目标类和 Reflector 工厂创建 MetaClass 对象 */ public static MetaClass forClass(Class<?> type, ReflectorFactory reflectorFactory) { return new MetaClass(type, reflectorFactory); } /** * 根据属性名获取属性的名称,比如将 "userName" 转换为 "user_name"。 * 如果没有找到,则返回 null。 */ public String findProperty(String name) { StringBuilder prop = buildProperty(name, new StringBuilder()); return prop.length() > 0 ? prop.toString() : null; } /** * 根据属性名获取属性的名称,比如将 "userName" 转换为 "user_name"。 * 如果没有找到,则返回 null。 * useCamelCaseMapping 参数用于指定是否使用驼峰命名法。 */ public String findProperty(String name, boolean useCamelCaseMapping) { if (useCamelCaseMapping) { name = name.replace("_", ""); } return findProperty(name); } /** * 获取所有可读的属性名 */ public String[] getGetterNames() { return reflector.getGetablePropertyNames(); } /** * 获取所有可写的属性名 */ public String[] getSetterNames() { return reflector.getSetablePropertyNames(); } /** * 根据属性名获取 setter 方法的参数类型 */ public Class<?> getSetterType(String name) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { MetaClass metaProp = metaClassForProperty(prop.getName()); return metaProp.getSetterType(prop.getChildren()); } return reflector.getSetterType(prop.getName()); } /** * 根据属性名获取 getter 方法的返回类型 */ public Class<?> getGetterType(String name) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { MetaClass metaProp = metaClassForProperty(prop); return metaProp.getGetterType(prop.getChildren()); } // issue #506. Resolve the type inside a Collection Object return getGetterType(prop); } /** * 根据属性名获取 getter 方法的返回类型 * 这个方法主要用于解析集合类型的泛型参数类型 */ private Class<?> getGetterType(PropertyTokenizer prop) { Class<?> type = reflector.getGetterType(prop.getName()); if (prop.getIndex() != null && Collection.class.isAssignableFrom(type)) { Type returnType = getGenericGetterType(prop.getName()); if (returnType instanceof ParameterizedType) { Type[] actualTypeArguments = ((ParameterizedType) returnType).getActualTypeArguments(); if (actualTypeArguments != null && actualTypeArguments.length == 1) { returnType = actualTypeArguments[0]; if (returnType instanceof Class) { type = (Class<?>) returnType; } else if (returnType instanceof ParameterizedType) { type = (Class<?>) ((ParameterizedType) returnType).getRawType(); } } } } return type; } /** * 获取 getter 方法的返回类型的泛型参数类型 */ private Type getGenericGetterType(String propertyName) { try { Invoker invoker = reflector.getGetInvoker(propertyName); if (invoker instanceof MethodInvoker) { Field declaredMethod = MethodInvoker.class.getDeclaredField("method"); declaredMethod.setAccessible(true); Method method = (Method) declaredMethod.get(invoker); return TypeParameterResolver.resolveReturnType(method, reflector.getType()); } if (invoker instanceof GetFieldInvoker) { Field declaredField = GetFieldInvoker.class.getDeclaredField("field"); declaredField.setAccessible(true); Field field = (Field) declaredField.get(invoker); return TypeParameterResolver.resolveFieldType(field, reflector.getType()); } } catch (NoSuchFieldException | IllegalAccessException e) { // Ignored } return null; } /** * 判断是否存在指定属性的 setter 方法 */ public boolean hasSetter(String name) { PropertyTokenizer prop = new PropertyTokenizer(name); if (!prop.hasNext()) { return reflector.hasSetter(prop.getName()); } if (reflector.hasSetter(prop.getName())) { MetaClass metaProp = metaClassForProperty(prop.getName()); return metaProp.hasSetter(prop.getChildren()); } else { return false; } } /** * 判断是否存在指定属性的 getter 方法 */ public boolean hasGetter(String name) { PropertyTokenizer prop = new PropertyTokenizer(name); if (!prop.hasNext()) { return reflector.hasGetter(prop.getName()); } if (reflector.hasGetter(prop.getName())) { MetaClass metaProp = metaClassForProperty(prop); return metaProp.hasGetter(prop.getChildren()); } else { return false; } } /** * 获取指定属性的 getter 方法对应的 Invoker 对象 */ public Invoker getGetInvoker(String name) { return reflector.getGetInvoker(name); } /** * 获取指定属性的 setter 方法对应的 Invoker 对象 */ public Invoker getSetInvoker(String name) { return reflector.getSetInvoker(name); } /** * 递归构建属性的名称,比如将 "user.name" 转换为 "user_name"。 */ private StringBuilder buildProperty(String name, StringBuilder builder) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { String propertyName = reflector.findPropertyName(prop.getName()); if (propertyName != null) { builder.append(propertyName); builder.append("."); MetaClass metaProp = metaClassForProperty(propertyName); metaProp.buildProperty(prop.getChildren(), builder); } } else { String propertyName = reflector.findPropertyName(name); if (propertyName != null) { builder.append(propertyName); } } return builder; } /** * 判断目标类是否有默认构造方法 */ public boolean hasDefaultConstructor() { return reflector.hasDefaultConstructor(); } /** * 根据属性名创建 MetaClass 对象 */ public MetaClass metaClassForProperty(String name) { Class<?> propType = reflector.getGetterType(name); return MetaClass.forClass(propType, reflectorFactory); } /** * 根据属性名创建 MetaClass 对象 */ private MetaClass metaClassForProperty(PropertyTokenizer prop) { Class<?> propType = getGetterType(prop); return MetaClass.forClass(propType, reflectorFactory); } }
2.5 测试
/* * Copyright 2009-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.ibatis.domain.misc; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class RichType { private RichType richType; private String richField; private String richProperty; private Map richMap = new HashMap<>(); private List richList = new ArrayList<>() { private static final long serialVersionUID = 1L; { add("bar"); } }; public RichType getRichType() { return richType; } public void setRichType(RichType richType) { this.richType = richType; } public String getRichProperty() { return richProperty; } public void setRichProperty(String richProperty) { this.richProperty = richProperty; } public List getRichList() { return richList; } public void setRichList(List richList) { this.richList = richList; } public Map getRichMap() { return richMap; } public void setRichMap(Map richMap) { this.richMap = richMap; } }
测试用例
/* * Copyright 2009-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.ibatis.reflection; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.ibatis.domain.blog.Author; import org.apache.ibatis.domain.blog.Section; import org.apache.ibatis.domain.misc.CustomBeanWrapper; import org.apache.ibatis.domain.misc.CustomBeanWrapperFactory; import org.apache.ibatis.domain.misc.RichType; import org.junit.jupiter.api.Test; class MetaObjectTest { @Test void shouldGetAndSetField() { RichType rich = new RichType(); MetaObject meta = SystemMetaObject.forObject(rich); meta.setValue("richField", "foo"); assertEquals("foo", meta.getValue("richField")); } @Test void shouldGetAndSetNestedField() { RichType rich = new RichType(); MetaObject meta = SystemMetaObject.forObject(rich); meta.setValue("richType.richField", "foo"); assertEquals("foo", meta.getValue("richType.richField")); } @Test void shouldGetAndSetProperty() { RichType rich = new RichType(); MetaObject meta = SystemMetaObject.forObject(rich); meta.setValue("richProperty", "foo"); assertEquals("foo", meta.getValue("richProperty")); } @Test void shouldGetAndSetNestedProperty() { RichType rich = new RichType(); MetaObject meta = SystemMetaObject.forObject(rich); meta.setValue("richType.richProperty", "foo"); assertEquals("foo", meta.getValue("richType.richProperty")); } @Test void shouldGetAndSetMapPair() { RichType rich = new RichType(); MetaObject meta = SystemMetaObject.forObject(rich); meta.setValue("richMap.key", "foo"); assertEquals("foo", meta.getValue("richMap.key")); } @Test void shouldGetAndSetMapPairUsingArraySyntax() { RichType rich = new RichType(); MetaObject meta = SystemMetaObject.forObject(rich); meta.setValue("richMap[key]", "foo"); assertEquals("foo", meta.getValue("richMap[key]")); } @Test void shouldGetAndSetNestedMapPair() { RichType rich = new RichType(); MetaObject meta = SystemMetaObject.forObject(rich); meta.setValue("richType.richMap.key", "foo"); assertEquals("foo", meta.getValue("richType.richMap.key")); } @Test void shouldGetAndSetNestedMapPairUsingArraySyntax() { RichType rich = new RichType(); MetaObject meta = SystemMetaObject.forObject(rich); meta.setValue("richType.richMap[key]", "foo"); assertEquals("foo", meta.getValue("richType.richMap[key]")); } @Test void shouldGetAndSetListItem() { RichType rich = new RichType(); MetaObject meta = SystemMetaObject.forObject(rich); meta.setValue("richList[0]", "foo"); assertEquals("foo", meta.getValue("richList[0]")); } @Test void shouldGetAndSetNestedListItem() { RichType rich = new RichType(); MetaObject meta = SystemMetaObject.forObject(rich); meta.setValue("richType.richList[0]", "foo"); assertEquals("foo", meta.getValue("richType.richList[0]")); } @Test void shouldGetReadablePropertyNames() { RichType rich = new RichType(); MetaObject meta = SystemMetaObject.forObject(rich); String[] readables = meta.getGetterNames(); assertEquals(5, readables.length); for (String readable : readables) { assertTrue(meta.hasGetter(readable)); assertTrue(meta.hasGetter("richType." + readable)); } assertTrue(meta.hasGetter("richType")); } @Test void shouldGetWriteablePropertyNames() { RichType rich = new RichType(); MetaObject meta = SystemMetaObject.forObject(rich); String[] writeables = meta.getSetterNames(); assertEquals(5, writeables.length); for (String writeable : writeables) { assertTrue(meta.hasSetter(writeable)); assertTrue(meta.hasSetter("richType." + writeable)); } assertTrue(meta.hasSetter("richType")); } @Test void shouldSetPropertyOfNullNestedProperty() { MetaObject richWithNull = SystemMetaObject.forObject(new RichType()); richWithNull.setValue("richType.richProperty", "foo"); assertEquals("foo", richWithNull.getValue("richType.richProperty")); } @Test void shouldSetPropertyOfNullNestedPropertyWithNull() { MetaObject richWithNull = SystemMetaObject.forObject(new RichType()); richWithNull.setValue("richType.richProperty", null); assertNull(richWithNull.getValue("richType.richProperty")); } @Test void shouldGetPropertyOfNullNestedProperty() { MetaObject richWithNull = SystemMetaObject.forObject(new RichType()); assertNull(richWithNull.getValue("richType.richProperty")); } @Test void shouldVerifyHasReadablePropertiesReturnedByGetReadablePropertyNames() { MetaObject object = SystemMetaObject.forObject(new Author()); for (String readable : object.getGetterNames()) { assertTrue(object.hasGetter(readable)); } } @Test void shouldVerifyHasWriteablePropertiesReturnedByGetWriteablePropertyNames() { MetaObject object = SystemMetaObject.forObject(new Author()); for (String writeable : object.getSetterNames()) { assertTrue(object.hasSetter(writeable)); } } @Test void shouldSetAndGetProperties() { MetaObject object = SystemMetaObject.forObject(new Author()); object.setValue("email", "test"); assertEquals("test", object.getValue("email")); } @Test void shouldVerifyPropertyTypes() { MetaObject object = SystemMetaObject.forObject(new Author()); assertEquals(6, object.getSetterNames().length); assertEquals(int.class, object.getGetterType("id")); assertEquals(String.class, object.getGetterType("username")); assertEquals(String.class, object.getGetterType("password")); assertEquals(String.class, object.getGetterType("email")); assertEquals(String.class, object.getGetterType("bio")); assertEquals(Section.class, object.getGetterType("favouriteSection")); } @Test void shouldDemonstrateDeeplyNestedMapProperties() { HashMap<String, String> map = new HashMap<>(); MetaObject metaMap = SystemMetaObject.forObject(map); assertTrue(metaMap.hasSetter("id")); assertTrue(metaMap.hasSetter("name.first")); assertTrue(metaMap.hasSetter("address.street")); assertFalse(metaMap.hasGetter("id")); assertFalse(metaMap.hasGetter("name.first")); assertFalse(metaMap.hasGetter("address.street")); metaMap.setValue("id", "100"); metaMap.setValue("name.first", "Clinton"); metaMap.setValue("name.last", "Begin"); metaMap.setValue("address.street", "1 Some Street"); metaMap.setValue("address.city", "This City"); metaMap.setValue("address.province", "A Province"); metaMap.setValue("address.postal_code", "1A3 4B6"); assertTrue(metaMap.hasGetter("id")); assertTrue(metaMap.hasGetter("name.first")); assertTrue(metaMap.hasGetter("address.street")); assertEquals(3, metaMap.getGetterNames().length); assertEquals(3, metaMap.getSetterNames().length); @SuppressWarnings("unchecked") Map<String, String> name = (Map<String, String>) metaMap.getValue("name"); @SuppressWarnings("unchecked") Map<String, String> address = (Map<String, String>) metaMap.getValue("address"); assertEquals("Clinton", name.get("first")); assertEquals("1 Some Street", address.get("street")); } @Test void shouldDemonstrateNullValueInMap() { HashMap<String, String> map = new HashMap<>(); MetaObject metaMap = SystemMetaObject.forObject(map); assertFalse(metaMap.hasGetter("phone.home")); metaMap.setValue("phone", null); assertTrue(metaMap.hasGetter("phone")); // hasGetter returns true if the parent exists and is null. assertTrue(metaMap.hasGetter("phone.home")); assertTrue(metaMap.hasGetter("phone.home.ext")); assertNull(metaMap.getValue("phone")); assertNull(metaMap.getValue("phone.home")); assertNull(metaMap.getValue("phone.home.ext")); metaMap.setValue("phone.office", "789"); assertFalse(metaMap.hasGetter("phone.home")); assertFalse(metaMap.hasGetter("phone.home.ext")); assertEquals("789", metaMap.getValue("phone.office")); assertNotNull(metaMap.getValue("phone")); assertNull(metaMap.getValue("phone.home")); } @Test void shouldMethodHasGetterReturnTrueWhenListElementSet() { List<Object> param1 = new ArrayList<>(); param1.add("firstParam"); param1.add(222); param1.add(new Date()); Map<String, Object> parametersEmulation = new HashMap<>(); parametersEmulation.put("param1", param1); parametersEmulation.put("filterParams", param1); MetaObject meta = SystemMetaObject.forObject(parametersEmulation); assertEquals(param1.get(0), meta.getValue("filterParams[0]")); assertEquals(param1.get(1), meta.getValue("filterParams[1]")); assertEquals(param1.get(2), meta.getValue("filterParams[2]")); assertTrue(meta.hasGetter("filterParams[0]")); assertTrue(meta.hasGetter("filterParams[1]")); assertTrue(meta.hasGetter("filterParams[2]")); } }