北京企业网站,导入表格做地图中热力网站,医疗网站几个人做竞价,开发一个公众号多少钱文章目录一、MetaObject基本使用二、关键类源码分析1、MetaObject的构造方法2、PropertyTokenizer分词器3、BeanWrapper4、MetaClass5、DefaultReflectorFactory6、Reflector7、总结三、MetaObject的getValue源码分析写在后面一、MetaObject基本使用
public class User {priva…
文章目录一、MetaObject基本使用二、关键类源码分析1、MetaObject的构造方法2、PropertyTokenizer分词器3、BeanWrapper4、MetaClass5、DefaultReflectorFactory6、Reflector7、总结三、MetaObject的getValue源码分析写在后面一、MetaObject基本使用
public class User {private int id;private String name;private String phoneNumber;private User child;ListUser users;private ListString likes;MapString, String labels;// get set
}Object user new User();
Configuration configuration new Configuration();
MetaObject metaObject configuration.newMetaObject(user);
// 直接属性赋值
metaObject.setValue(name, zhangsan);
System.out.println(metaObject.getValue(name));// 子属性赋值对象为null会自动创建并填充属性值
metaObject.setValue(child.name, lisi);
System.out.println(metaObject.getValue(child.name));// 查找驼峰属性 phoneNumber
System.out.println(metaObject.findProperty(phone_number, true));// 操作数组基于索引操作数组
ArrayListString strings new ArrayList();
strings.add(sing);
strings.add(run);
metaObject.setValue(likes, strings);
System.out.println(metaObject.getValue(likes));
System.out.println(metaObject.getValue(likes[0])); // 获取第一个// 操作Map
metaObject.setValue(labels, new HashMapString, String());
metaObject.setValue(labels[red], like);
metaObject.setValue(labels[blue], notLike);
System.out.println(metaObject.getValue(labels));
System.out.println(metaObject.getValue(labels[red]));MetaObject是一个强大的反射工具类 支持查找属性忽略大小写、支持驼峰、支持子属性、 查找子属性“user.name”、users[0].id获取集合中子属性的值、user[name]获取map、 支持设置子属性自动创建子属性必须带有空参构造方法且不能是集合。
MetaObject工具类不止设置、查找属性值还提供了获取set、get方法、查找属性值等反射常用方法。
二、关键类源码分析
1、MetaObject的构造方法
调用MetaObject 的forObject方法可以将Object对象转换成BeanWrapper对象最终调用了new BeanWrapper
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);}
}public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {if (object null) {return SystemMetaObject.NULL_META_OBJECT;} else {return new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory);}
}2、PropertyTokenizer分词器
public class PropertyTokenizer implements IteratorPropertyTokenizer {private String name; // 属性名称private final String indexedName; // 带着索引的属性名称private String index; // 索引如果有的话private final String children; // 除了indexedName之外的剩余的表达式名称 // 构造方法根据 . 来进行分词分词完毕后会将以上四个属性初始化好public PropertyTokenizer(String fullname) {int delim fullname.indexOf(.);if (delim -1) {name fullname.substring(0, delim);children fullname.substring(delim 1);} else {name fullname;children null;}indexedName name;delim name.indexOf([);if (delim -1) {index name.substring(delim 1, name.length() - 1);name name.substring(0, delim);}}public String getName() {return name;}public String getIndex() {return index;}public String getIndexedName() {return indexedName;}public String getChildren() {return children;}// 判断是否有子节点Overridepublic boolean hasNext() {return children ! null;}// 创建子节点时也是new一个PropertyTokenizer分词器重复操作Overridepublic PropertyTokenizer next() {return new PropertyTokenizer(children);}Overridepublic void remove() {throw new UnsupportedOperationException(Remove is not supported, as it has no meaning in the context of properties.);}
}3、BeanWrapper
BeanWrapper的构造方法将原始对象和metaObject对象进行存储并调用MetaClass的forClass方法解析Object原始对象的基本数据。
BeanWrapper中提供了获取Object原始对象的 设置值、获取值、获取getset方法、获取属性、获取setget类型等等一系列核心操作方法最终都是委派给MetaClass 来实现的。
public class BeanWrapper extends BaseWrapper {private final Object object;private final MetaClass metaClass;public BeanWrapper(MetaObject metaObject, Object object) {super(metaObject);this.object object;this.metaClass MetaClass.forClass(object.getClass(), metaObject.getReflectorFactory());}Overridepublic Object get(PropertyTokenizer prop) {if (prop.getIndex() ! null) {Object collection resolveCollection(prop, object);return getCollectionValue(prop, collection);} else {return getBeanProperty(prop, object);}}Overridepublic void set(PropertyTokenizer prop, Object value) {if (prop.getIndex() ! null) {Object collection resolveCollection(prop, object);setCollectionValue(prop, collection, value);} else {setBeanProperty(prop, object, value);}}Overridepublic String findProperty(String name, boolean useCamelCaseMapping) {return metaClass.findProperty(name, useCamelCaseMapping);}Overridepublic String[] getGetterNames() {return metaClass.getGetterNames();}Overridepublic String[] getSetterNames() {return metaClass.getSetterNames();}Overridepublic 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 metaClass.getSetterType(name);} else {return metaValue.getSetterType(prop.getChildren());}} else {return metaClass.getSetterType(name);}}Overridepublic 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);}}Overridepublic 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);}}Overridepublic 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);}}Overridepublic 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) {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;}private Object getBeanProperty(PropertyTokenizer prop, Object object) {try {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);}}private void setBeanProperty(PropertyTokenizer prop, Object object, Object value) {try {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);}}Overridepublic boolean isCollection() {return false;}Overridepublic void add(Object element) {throw new UnsupportedOperationException();}Overridepublic E void addAll(ListE list) {throw new UnsupportedOperationException();}}4、MetaClass
在MetaClass的构造方法中通过ReflectorFactory反射工厂的findForClass将原始的Object进行解析最终将解析的结果存放到Reflector成员变量中。
在MetaClass的核心方法大多数操作的底层都是操作Reflector来进行实现的。
public class MetaClass {private final ReflectorFactory reflectorFactory;private final Reflector reflector;private MetaClass(Class? type, ReflectorFactory reflectorFactory) {this.reflectorFactory reflectorFactory;this.reflector reflectorFactory.findForClass(type);}public static MetaClass forClass(Class? type, ReflectorFactory reflectorFactory) {return new MetaClass(type, reflectorFactory);}public MetaClass metaClassForProperty(String name) {Class? propType reflector.getGetterType(name);return MetaClass.forClass(propType, reflectorFactory);}public String findProperty(String name) {StringBuilder prop buildProperty(name, new StringBuilder());return prop.length() 0 ? prop.toString() : null;}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();}public Class? getSetterType(String name) {PropertyTokenizer prop new PropertyTokenizer(name);if (prop.hasNext()) {MetaClass metaProp metaClassForProperty(prop.getName());return metaProp.getSetterType(prop.getChildren());} else {return reflector.getSetterType(prop.getName());}}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 Objectreturn getGetterType(prop);}private MetaClass metaClassForProperty(PropertyTokenizer prop) {Class? propType getGetterType(prop);return MetaClass.forClass(propType, reflectorFactory);}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;}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());} else 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;}public boolean hasSetter(String name) {PropertyTokenizer prop new PropertyTokenizer(name);if (prop.hasNext()) {if (reflector.hasSetter(prop.getName())) {MetaClass metaProp metaClassForProperty(prop.getName());return metaProp.hasSetter(prop.getChildren());} else {return false;}} else {return reflector.hasSetter(prop.getName());}}public boolean hasGetter(String name) {PropertyTokenizer prop new PropertyTokenizer(name);if (prop.hasNext()) {if (reflector.hasGetter(prop.getName())) {MetaClass metaProp metaClassForProperty(prop);return metaProp.hasGetter(prop.getChildren());} else {return false;}} else {return reflector.hasGetter(prop.getName());}}public Invoker getGetInvoker(String name) {return reflector.getGetInvoker(name);}public Invoker getSetInvoker(String name) {return reflector.getSetInvoker(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();}}
5、DefaultReflectorFactory
DefaultReflectorFactory实现了ReflectorFactory用于生成Reflector
public class DefaultReflectorFactory implements ReflectorFactory {private boolean classCacheEnabled true;private final ConcurrentMapClass?, Reflector reflectorMap new ConcurrentHashMap();public DefaultReflectorFactory() {}Overridepublic boolean isClassCacheEnabled() {return classCacheEnabled;}Overridepublic void setClassCacheEnabled(boolean classCacheEnabled) {this.classCacheEnabled classCacheEnabled;}Overridepublic Reflector findForClass(Class? type) {if (classCacheEnabled) {// synchronized (type) removed see issue #461return MapUtil.computeIfAbsent(reflectorMap, type, Reflector::new);} else {return new Reflector(type);}}}
6、Reflector
这是MyBatis的反射最底层类构造方法中将原始的对象Class进行解析所有的方法、属性等等都存放到这里用于存储。
public class Reflector {private final Class? type;private final String[] readablePropertyNames;private final String[] writablePropertyNames;private final MapString, Invoker setMethods new HashMap();private final MapString, Invoker getMethods new HashMap();private final MapString, Class? setTypes new HashMap();private final MapString, Class? getTypes new HashMap();private Constructor? defaultConstructor;private MapString, String caseInsensitivePropertyMap new HashMap();public Reflector(Class? clazz) {type clazz;addDefaultConstructor(clazz);addGetMethods(clazz);addSetMethods(clazz);addFields(clazz);readablePropertyNames getMethods.keySet().toArray(new String[0]);writablePropertyNames setMethods.keySet().toArray(new String[0]);for (String propName : readablePropertyNames) {caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);}for (String propName : writablePropertyNames) {caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);}}private void addDefaultConstructor(Class? clazz) {Constructor?[] constructors clazz.getDeclaredConstructors();Arrays.stream(constructors).filter(constructor - constructor.getParameterTypes().length 0).findAny().ifPresent(constructor - this.defaultConstructor constructor);}private void addGetMethods(Class? clazz) {MapString, ListMethod conflictingGetters new HashMap();Method[] methods getClassMethods(clazz);Arrays.stream(methods).filter(m - m.getParameterTypes().length 0 PropertyNamer.isGetter(m.getName())).forEach(m - addMethodConflict(conflictingGetters, PropertyNamer.methodToProperty(m.getName()), m));resolveGetterConflicts(conflictingGetters);}private void resolveGetterConflicts(MapString, ListMethod conflictingGetters) {for (EntryString, ListMethod entry : conflictingGetters.entrySet()) {Method winner null;String propName entry.getKey();boolean isAmbiguous false;for (Method candidate : entry.getValue()) {if (winner null) {winner candidate;continue;}Class? winnerType winner.getReturnType();Class? candidateType candidate.getReturnType();if (candidateType.equals(winnerType)) {if (!boolean.class.equals(candidateType)) {isAmbiguous true;break;} else if (candidate.getName().startsWith(is)) {winner candidate;}} else if (candidateType.isAssignableFrom(winnerType)) {// OK getter type is descendant} else if (winnerType.isAssignableFrom(candidateType)) {winner candidate;} else {isAmbiguous true;break;}}addGetMethod(propName, winner, isAmbiguous);}}private void addGetMethod(String name, Method method, boolean isAmbiguous) {MethodInvoker invoker isAmbiguous? new AmbiguousMethodInvoker(method, MessageFormat.format(Illegal overloaded getter method with ambiguous type for property {0} in class {1}. This breaks the JavaBeans specification and can cause unpredictable results.,name, method.getDeclaringClass().getName())): new MethodInvoker(method);getMethods.put(name, invoker);Type returnType TypeParameterResolver.resolveReturnType(method, type);getTypes.put(name, typeToClass(returnType));}private void addSetMethods(Class? clazz) {MapString, ListMethod conflictingSetters new HashMap();Method[] methods getClassMethods(clazz);Arrays.stream(methods).filter(m - m.getParameterTypes().length 1 PropertyNamer.isSetter(m.getName())).forEach(m - addMethodConflict(conflictingSetters, PropertyNamer.methodToProperty(m.getName()), m));resolveSetterConflicts(conflictingSetters);}private void addMethodConflict(MapString, ListMethod conflictingMethods, String name, Method method) {if (isValidPropertyName(name)) {ListMethod list MapUtil.computeIfAbsent(conflictingMethods, name, k - new ArrayList());list.add(method);}}private void resolveSetterConflicts(MapString, ListMethod conflictingSetters) {for (EntryString, ListMethod entry : conflictingSetters.entrySet()) {String propName entry.getKey();ListMethod setters entry.getValue();Class? getterType getTypes.get(propName);boolean isGetterAmbiguous getMethods.get(propName) instanceof AmbiguousMethodInvoker;boolean isSetterAmbiguous false;Method match null;for (Method setter : setters) {if (!isGetterAmbiguous setter.getParameterTypes()[0].equals(getterType)) {// should be the best matchmatch setter;break;}if (!isSetterAmbiguous) {match pickBetterSetter(match, setter, propName);isSetterAmbiguous match null;}}if (match ! null) {addSetMethod(propName, match);}}}private Method pickBetterSetter(Method setter1, Method setter2, String property) {if (setter1 null) {return setter2;}Class? paramType1 setter1.getParameterTypes()[0];Class? paramType2 setter2.getParameterTypes()[0];if (paramType1.isAssignableFrom(paramType2)) {return setter2;} else if (paramType2.isAssignableFrom(paramType1)) {return setter1;}MethodInvoker invoker new AmbiguousMethodInvoker(setter1,MessageFormat.format(Ambiguous setters defined for property {0} in class {1} with types {2} and {3}.,property, setter2.getDeclaringClass().getName(), paramType1.getName(), paramType2.getName()));setMethods.put(property, invoker);Type[] paramTypes TypeParameterResolver.resolveParamTypes(setter1, type);setTypes.put(property, typeToClass(paramTypes[0]));return null;}private void addSetMethod(String name, Method method) {MethodInvoker invoker new MethodInvoker(method);setMethods.put(name, invoker);Type[] paramTypes TypeParameterResolver.resolveParamTypes(method, type);setTypes.put(name, typeToClass(paramTypes[0]));}private Class? typeToClass(Type src) {Class? result null;if (src instanceof Class) {result (Class?) src;} else if (src instanceof ParameterizedType) {result (Class?) ((ParameterizedType) src).getRawType();} else if (src instanceof GenericArrayType) {Type componentType ((GenericArrayType) src).getGenericComponentType();if (componentType instanceof Class) {result Array.newInstance((Class?) componentType, 0).getClass();} else {Class? componentClass typeToClass(componentType);result Array.newInstance(componentClass, 0).getClass();}}if (result null) {result Object.class;}return result;}private void addFields(Class? clazz) {Field[] fields clazz.getDeclaredFields();for (Field field : fields) {if (!setMethods.containsKey(field.getName())) {// issue #379 - removed the check for final because JDK 1.5 allows// modification of final fields through reflection (JSR-133). (JGB)// pr #16 - final static can only be set by the classloaderint modifiers field.getModifiers();if (!(Modifier.isFinal(modifiers) Modifier.isStatic(modifiers))) {addSetField(field);}}if (!getMethods.containsKey(field.getName())) {addGetField(field);}}if (clazz.getSuperclass() ! null) {addFields(clazz.getSuperclass());}}private void addSetField(Field field) {if (isValidPropertyName(field.getName())) {setMethods.put(field.getName(), new SetFieldInvoker(field));Type fieldType TypeParameterResolver.resolveFieldType(field, type);setTypes.put(field.getName(), typeToClass(fieldType));}}private void addGetField(Field field) {if (isValidPropertyName(field.getName())) {getMethods.put(field.getName(), new GetFieldInvoker(field));Type fieldType TypeParameterResolver.resolveFieldType(field, type);getTypes.put(field.getName(), typeToClass(fieldType));}}private boolean isValidPropertyName(String name) {return !(name.startsWith($) || serialVersionUID.equals(name) || class.equals(name));}/*** This method returns an array containing all methods* declared in this class and any superclass.* We use this method, instead of the simpler codeClass.getMethods()/code,* because we want to look for private methods as well.** param clazz The class* return An array containing all methods in this class*/private Method[] getClassMethods(Class? clazz) {MapString, Method uniqueMethods new HashMap();Class? currentClass clazz;while (currentClass ! null currentClass ! Object.class) {addUniqueMethods(uniqueMethods, currentClass.getDeclaredMethods());// we also need to look for interface methods -// because the class may be abstractClass?[] interfaces currentClass.getInterfaces();for (Class? anInterface : interfaces) {addUniqueMethods(uniqueMethods, anInterface.getMethods());}currentClass currentClass.getSuperclass();}CollectionMethod methods uniqueMethods.values();return methods.toArray(new Method[0]);}private void addUniqueMethods(MapString, Method uniqueMethods, Method[] methods) {for (Method currentMethod : methods) {if (!currentMethod.isBridge()) {String signature getSignature(currentMethod);// check to see if the method is already known// if it is known, then an extended class must have// overridden a methodif (!uniqueMethods.containsKey(signature)) {uniqueMethods.put(signature, currentMethod);}}}}private String getSignature(Method method) {StringBuilder sb new StringBuilder();Class? returnType method.getReturnType();if (returnType ! null) {sb.append(returnType.getName()).append(#);}sb.append(method.getName());Class?[] parameters method.getParameterTypes();for (int i 0; i parameters.length; i) {sb.append(i 0 ? : : ,).append(parameters[i].getName());}return sb.toString();}/*** Checks whether can control member accessible.** return If can control member accessible, it return {literal true}* since 3.5.0*/public static boolean canControlMemberAccessible() {try {SecurityManager securityManager System.getSecurityManager();if (null ! securityManager) {securityManager.checkPermission(new ReflectPermission(suppressAccessChecks));}} catch (SecurityException e) {return false;}return true;}/*** Gets the name of the class the instance provides information for.** return The class name*/public Class? getType() {return type;}public Constructor? getDefaultConstructor() {if (defaultConstructor ! null) {return defaultConstructor;} else {throw new ReflectionException(There is no default constructor for type);}}public boolean hasDefaultConstructor() {return defaultConstructor ! null;}public Invoker getSetInvoker(String propertyName) {Invoker method setMethods.get(propertyName);if (method null) {throw new ReflectionException(There is no setter for property named propertyName in type );}return method;}public Invoker getGetInvoker(String propertyName) {Invoker method getMethods.get(propertyName);if (method null) {throw new ReflectionException(There is no getter for property named propertyName in type );}return method;}/*** Gets the type for a property setter.** param propertyName - the name of the property* return The Class of the property setter*/public Class? getSetterType(String propertyName) {Class? clazz setTypes.get(propertyName);if (clazz null) {throw new ReflectionException(There is no setter for property named propertyName in type );}return clazz;}/*** Gets the type for a property getter.** param propertyName - the name of the property* return The Class of the property getter*/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;}/*** Gets an array of the readable properties for an object.** return The array*/public String[] getGetablePropertyNames() {return readablePropertyNames;}/*** Gets an array of the writable properties for an object.** return The array*/public String[] getSetablePropertyNames() {return writablePropertyNames;}/*** Check to see if a class has a writable property by name.** param propertyName - the name of the property to check* return True if the object has a writable property by the name*/public boolean hasSetter(String propertyName) {return setMethods.containsKey(propertyName);}/*** Check to see if a class has a readable property by name.** param propertyName - the name of the property to check* return True if the object has a readable property by the name*/public boolean hasGetter(String propertyName) {return getMethods.containsKey(propertyName);}public String findPropertyName(String name) {return caseInsensitivePropertyMap.get(name.toUpperCase(Locale.ENGLISH));}
}
7、总结
MyBatis的MetaObject反射工具类可以说是MyBatis的底层类几乎不与MyBatis有耦合如果项目中也需要这样一个工具类可以“拿来即用”或者稍加修改就可以拿来使用。非常强大。 图片来自于鲁班大叔
三、MetaObject的getValue源码分析
我们以这样一个表达式为例进行源码分析
// 获取对象中users的第一个元素中的child属性中的name属性
metaObject.getValue(users[0].child.name);MetaObject的getValue核心源码
// org.apache.ibatis.reflection.MetaObject#getValue
public Object getValue(String name) {// 创建属性分词器将users[0].child.name创建一个nameusers;indexedNameusers[0];index0;childrenchild.name的分词器PropertyTokenizer prop new PropertyTokenizer(name); if (prop.hasNext()) { // 是否有下一个子节点MetaObject metaValue metaObjectForProperty(prop.getIndexedName());// 继续构造一个MetaObject对象是users[0]if (metaValue SystemMetaObject.NULL_META_OBJECT) { // 如果是null直接返回return null;} else { // 如果不是null就递归调用getValue方法直到查找到最后一个属性return metaValue.getValue(prop.getChildren()); }} else { // 如果没有子节点通过反射调用get方法获取属性return objectWrapper.get(prop);}
}写在后面
如果本文对你有帮助请点赞收藏关注一下吧 ~