当前位置: 首页 > news >正文

知名网站建设公司排名/微信公众号怎么开通

知名网站建设公司排名,微信公众号怎么开通,委托别人建设网站的合同的版本,网站开发培训流程历时漫长的岁月,终于鼓起勇气继续研究Mybatis的反射工具类们,简直就是把反射玩出花,但是理解起来还是很有难度的,涉及的内容代码也颇多,所以花费时间也比较浩大,不过当了解套路每个类的功能也好&#xff0c…

历时漫长的岁月,终于鼓起勇气继续研究Mybatis的反射工具类们,简直就是把反射玩出花,但是理解起来还是很有难度的,涉及的内容代码也颇多,所以花费时间也比较浩大,不过当了解套路每个类的功能也好,设计也好,基本也可以浓缩成一句话理解,心中有了系统也好似没有那么难理解了,本节如在工作中使用到此场景,可以拿来当作工具直接使用。

  1. 前言-为什么使用反射

在手敲Mybatis-数据源池化处理实现那一节,我们留下了坑需要填,在获取连接时,数据库连接的设置还是硬编码,如果我们此时xml文件又需要新增加一些属性,就需要进行修改代码,会发现代码设计不太灵活,本节就为了解决此问题,来一起写一个很强大的反射工具类。

  1. UML类图-类关系介绍

MyBatis设计将分为以下几个类,元类、元对象、对象包装器、反射器、调用者、对象工厂,下面就介绍这几个设计都是干什么的:

SystemMetaObject:系统入口,万物的开始,系统级别的元对象

MetaObject:元对象,外部系统调用入口,封装了包装器对象,在构造方法中使用策略模式来调用不同的对象包装器

MetaClass:元类,通过对象包装器进入,此类是对反射器的封装并进一步进行处理某些场景复杂操作

Reflector:反射器,解析对象的属性、方法、类型的解析器,最后组装起来,提供基础的方法获取数据

ObjectWrapper:对象包装器接口,定义对象基本信息

BaseWrapper:基础包装器,抽取共用包装器方法,解析集合获取集合设置集合等处理

BeanWrapper:原生包装器,对bean对象进行处理,由此方法进入MetaClass类最后进入 Reflector反射将对象数据得到。

CollectionWrapper:原生集合包装器

MapWrapper:map集合包装器,处理map对象

ObjectWrapperFactory:对象包装器工厂接口,可以获取对象包装器

DefaultObjectWrapperFactory:实现对象包装器工厂接口

ObjectFactory:对象工厂接口

DefaultObjectFactory:默认对象工厂接口,创建对象实例处理

Invoker: 调用者接口,定义反射调用

MethodInvoker:方法调用者,反射方法的

GetFieldInvoker此类用于执行读取属性值的反射操作

SetFieldInvoker:用于执行设置属性值的反射操作

PropertyNamer:属性命名器,会将方法转换为属性名称

PropertyTokenizer :属性解析器,属性也不只有单一属性也会有复杂属性,例如属性.属性,集合等

执行流程:SystemMetaObject-->MetaObject-->ObjectWrapper-->MetaClass-->Reflector-->Invoker

而属解析器在处理中有时各个类都会用,反射器工具类要用的就这个20个类,想必你通过介绍大大致对它有印象了,可以对应看下uml图理解理解

  1. 完整代码实现

3.1 反射调用者

package df.middleware.mybatis.reflection.invoker

Invoker:反射调用者接口,定义invoke方法,子类具体实现对应的调用者,因为反射调用离不开目标对象和参数,所以此接口统一定义invoke()。

/*** @description 调用者接口* @date 2022/5/2* 此接口的作用统一基于反射处理方法和属性的调用方式,采取策略模式*/
public interface Invoker {/*** 执行反射操作** @param target 方法或者属性执行的目标对象* @param args   方法或者属性执行时依赖的参数*/Object invoke(Object target, Object[] args) throws Exception;/***方法或者属性对应的类型*/Class<?> getType();}

MethodInvoker:方法调用者,构造函数会传对应的目标方method,再通过反射进行调用目标方法

/*** @description 方法调用者* 用于执行方法的反射操作*/
public class MethodInvoker implements Invoker {private Class<?> type;private Method method;/*** 如果方法是getter方法,则表示返回值类型* 如果方法是setter方法,则表示入参类型*/public MethodInvoker(Method method) {this.method = method;// 利用方法是否有无入参判断方法是get还是set方法,// 如果只有一个参数,返回参数类型,否则返回 return 类型if (method.getParameterTypes().length == 1) {// set方法获取方法入参类型赋给type属性type = method.getParameterTypes()[0];} else {// get方法则获取方法返回类型赋给type属性type = method.getReturnType();}}@Overridepublic Object invoke(Object target, Object[] args) throws Exception {// 执行方法return method.invoke(target, args);}@Overridepublic Class<?> getType() {return type;}}

GetFieldInvoker:获取属性调用者,构造函数会传目标属性Field,通过反射获取属性值并返回

/*** @description getter 调用者* 属性是会有set和get的,所以字段会有GetFieldInvoker和SetFieldInvoker* 此类用于执行读取属性值的反射操作*/
public class GetFieldInvoker implements Invoker {private Field field;public GetFieldInvoker(Field field) {this.field = field;}@Overridepublic Object invoke(Object target, Object[] args) throws Exception {// 基于反射获取指定属性值return field.get(target);}// 获取对应属性的类型@Overridepublic Class<?> getType() {return field.getType();}
}

SetFieldInvoker:设置属性调用者,构造函数会传目标属性Field,通过反射给目标属性设置值,设置是不返回的,这里就返回空

/*** @description setter 调用者* 用于执行设置属性值的反射操作*/
public class SetFieldInvoker implements Invoker {private Field field;public SetFieldInvoker(Field field) {this.field = field;}@Overridepublic Object invoke(Object target, Object[] args) throws Exception {// 为指定属性设置值的功能field.set(target, args[0]);return null;}@Overridepublic Class<?> getType() {return field.getType();}
}

3.2反射器

Reflector:反射器,这个类代码相对很多,大体主要是用反射将对象信息解析出来,如类里的默认构造方法,以及属性和方法等等,解析出来处理成我们想要的数据以后存储各个容器里。这样我们数据有了,还需要添加一些对外获取容器数据的公共方法,这就是这个类的全部职责,其实也还好,就是代码多些,但是知道大致处理内容,也就没有那么难理解了,需要多debug熟悉。

/***  反射器,属性 get/set 的映射器* */
public class Reflector {private static boolean classCacheEnabled = true;private static final String[] EMPTY_STRING_ARRAY = new String[0];// 线程安全的缓存private static final Map<Class<?>, Reflector> REFLECTOR_MAP = new ConcurrentHashMap<>();private Class<?> type;/*** get 属性列表,可读属性名称数组,用于保存 getter 方法对应的属性名称* */private String[] readablePropertyNames = EMPTY_STRING_ARRAY;/*** set 属性列表,可写属性名称数组,用于保存 setter 方法对应的属性名称* */private String[] writeablePropertyNames = EMPTY_STRING_ARRAY;/*** set 方法列表,* 用于保存属性名称到 Invoke 的映射。setter 方法会被封装到 MethodInvoker 对象中* */private Map<String, Invoker> setMethods = new HashMap<>();/*** get 方法列表* 用于保存属性名称到 Invoke 的映射。同上,getter 方法也会被封装到 MethodInvoker 对象中* */private Map<String, Invoker> getMethods = new HashMap<>();/*** 用于保存 setter 对应的属性名与参数类型的映射* */private Map<String, Class<?>> setTypes = new HashMap<>();/*** 用于保存 getter 对应的属性名与返回值类型的映射* */private Map<String, Class<?>> getTypes = new HashMap<>();// 默认构造函数private Constructor<?> defaultConstructor;/*** 用于保存大写属性名与属性名之间的映射,比如 <NAME, name>* */private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();// 解析所有的属性和方法并把数据处理到全局变量里public Reflector(Class<?> clazz) {this.type = clazz;// 加入构造函数addDefaultConstructor(clazz);// 反射解析getter方法加入 getterMethodsaddGetMethods(clazz);// 反射解析setter方法加入 setterMethods addSetMethods(clazz);// 反射解析字段数据,加入字段addFields(clazz);readablePropertyNames = getMethods.keySet().toArray(new String[getMethods.keySet().size()]);writeablePropertyNames = setMethods.keySet().toArray(new String[setMethods.keySet().size()]);for (String propName : readablePropertyNames) {caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);}for (String propName : writeablePropertyNames) {caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);}}private void addDefaultConstructor(Class<?> clazz) {Constructor<?>[] consts = clazz.getDeclaredConstructors();for (Constructor<?> constructor : consts) {if (constructor.getParameterTypes().length == 0) {if (canAccessPrivateMethods()) {try {constructor.setAccessible(true);} catch (Exception ignore) {// Ignored. This is only a final precaution, nothing we can do}}if (constructor.isAccessible()) {this.defaultConstructor = constructor;}}}}private void addGetMethods(Class<?> clazz) {Map<String, List<Method>> conflictingGetters = new HashMap<>();// 获取类中的方法Method[] methods = getClassMethods(clazz);for (Method method : methods) {String name = method.getName();if (name.startsWith("get") && name.length() > 3) {if (method.getParameterTypes().length == 0) {name = PropertyNamer.methodToProperty(name);addMethodConflict(conflictingGetters, name, method);}} else if (name.startsWith("is") && name.length() > 2) {if (method.getParameterTypes().length == 0) {name = PropertyNamer.methodToProperty(name);addMethodConflict(conflictingGetters, name, method);}}}resolveGetterConflicts(conflictingGetters);}private void addSetMethods(Class<?> clazz) {Map<String, List<Method>> conflictingSetters = new HashMap<>();Method[] methods = getClassMethods(clazz);for (Method method : methods) {String name = method.getName();if (name.startsWith("set") && name.length() > 3) {if (method.getParameterTypes().length == 1) {name = PropertyNamer.methodToProperty(name);addMethodConflict(conflictingSetters, name, method);}}}resolveSetterConflicts(conflictingSetters);}private void resolveSetterConflicts(Map<String, List<Method>> conflictingSetters) {for (String propName : conflictingSetters.keySet()) {List<Method> setters = conflictingSetters.get(propName);Method firstMethod = setters.get(0);if (setters.size() == 1) {addSetMethod(propName, firstMethod);} else {Class<?> expectedType = getTypes.get(propName);if (expectedType == null) {throw new RuntimeException("Illegal overloaded setter method with ambiguous type for property "+ propName + " in class " + firstMethod.getDeclaringClass() + ".  This breaks the JavaBeans " +"specification and can cause unpredicatble results.");} else {Iterator<Method> methods = setters.iterator();Method setter = null;while (methods.hasNext()) {Method method = methods.next();if (method.getParameterTypes().length == 1&& expectedType.equals(method.getParameterTypes()[0])) {setter = method;break;}}if (setter == null) {throw new RuntimeException("Illegal overloaded setter method with ambiguous type for property "+ propName + " in class " + firstMethod.getDeclaringClass() + ".  This breaks the JavaBeans " +"specification and can cause unpredicatble results.");}addSetMethod(propName, setter);}}}}// 加入set方法以MethodInvoker放入全局变量里private void addSetMethod(String name, Method method) {if (isValidPropertyName(name)) {setMethods.put(name, new MethodInvoker(method));setTypes.put(name, method.getParameterTypes()[0]);}}private void addFields(Class<?> clazz) {Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {if (canAccessPrivateMethods()) {try {field.setAccessible(true);} catch (Exception e) {// Ignored. This is only a final precaution, nothing we can do.}}if (field.isAccessible()) {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));setTypes.put(field.getName(), field.getType());}}private void addGetField(Field field) {if (isValidPropertyName(field.getName())) {getMethods.put(field.getName(), new GetFieldInvoker(field));getTypes.put(field.getName(), field.getType());}}private void resolveGetterConflicts(Map<String, List<Method>> conflictingGetters) {for (String propName : conflictingGetters.keySet()) {List<Method> getters = conflictingGetters.get(propName);Iterator<Method> iterator = getters.iterator();Method firstMethod = iterator.next();if (getters.size() == 1) {// 存放全局变量里addGetMethod(propName, firstMethod);} else {// 多个方法情况Method getter = firstMethod;Class<?> getterType = firstMethod.getReturnType();while (iterator.hasNext()) {Method method = iterator.next();Class<?> methodType = method.getReturnType();if (methodType.equals(getterType)) {throw new RuntimeException("Illegal overloaded getter method with ambiguous type for property "+ propName + " in class " + firstMethod.getDeclaringClass()+ ".  This breaks the JavaBeans " + "specification and can cause unpredicatble results.");} else if (methodType.isAssignableFrom(getterType)) {// OK getter type is descendant} else if (getterType.isAssignableFrom(methodType)) {getter = method;getterType = methodType;} else {throw new RuntimeException("Illegal overloaded getter method with ambiguous type for property "+ propName + " in class " + firstMethod.getDeclaringClass()+ ".  This breaks the JavaBeans " + "specification and can cause unpredicatble results.");}}addGetMethod(propName, getter);}}}// 加入get方法以MethodInvoker放入全局变量里private void addGetMethod(String name, Method method) {if (isValidPropertyName(name)) {getMethods.put(name, new MethodInvoker(method));getTypes.put(name, method.getReturnType());}}private boolean isValidPropertyName(String name) {return !(name.startsWith("$") || "serialVersionUID".equals(name) || "class".equals(name));}private void addMethodConflict(Map<String, List<Method>> conflictingMethods, String name, Method method) {List<Method> list = conflictingMethods.computeIfAbsent(name, k -> new ArrayList<>());list.add(method);}// 查找当前类及父类方法private Method[] getClassMethods(Class<?> cls) {Map<String, Method> uniqueMethods = new HashMap<String, Method>();Class<?> currentClass = cls;while (currentClass != null) {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();}Collection<Method> methods = uniqueMethods.values();return methods.toArray(new Method[methods.size()]);}// 校验方法唯一性,暂存临时集合private void addUniqueMethods(Map<String, 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)) {if (canAccessPrivateMethods()) {try {currentMethod.setAccessible(true);} catch (Exception e) {// Ignored. This is only a final precaution, nothing we can do.}}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++) {if (i == 0) {sb.append(':');} else {sb.append(',');}sb.append(parameters[i].getName());}return sb.toString();}private static boolean canAccessPrivateMethods() {try {SecurityManager securityManager = System.getSecurityManager();if (null != securityManager) {securityManager.checkPermission(new ReflectPermission("suppressAccessChecks"));}} catch (SecurityException e) {return false;}return true;}public Class<?> getType() {return type;}// -------------------------------------------解析并存储的数据需要对外提供基础容器获取---------------public Constructor<?> getDefaultConstructor() {if (defaultConstructor != null) {return defaultConstructor;} else {throw new RuntimeException("There is no default constructor for " + type);}}public boolean hasDefaultConstructor() {return defaultConstructor != null;}public Class<?> getSetterType(String propertyName) {Class<?> clazz = setTypes.get(propertyName);if (clazz == null) {throw new RuntimeException("There is no setter for property named '" + propertyName + "' in '" + type + "'");}return clazz;}public Invoker getGetInvoker(String propertyName) {Invoker method = getMethods.get(propertyName);if (method == null) {throw new RuntimeException("There is no getter for property named '" + propertyName + "' in '" + type + "'");}return method;}public Invoker getSetInvoker(String propertyName) {Invoker method = setMethods.get(propertyName);if (method == null) {throw new RuntimeException("There is no setter for property named '" + propertyName + "' in '" + type + "'");}return method;}/** Gets the type for a property getter** @param propertyName - the name of the property* @return The Class of the propery getter*/public Class<?> getGetterType(String propertyName) {Class<?> clazz = getTypes.get(propertyName);if (clazz == null) {throw new RuntimeException("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 writeable properties for an object** @return The array*/public String[] getSetablePropertyNames() {return writeablePropertyNames;}/** Check to see if a class has a writeable property by name** @param propertyName - the name of the property to check* @return True if the object has a writeable property by the name*/public boolean hasSetter(String propertyName) {return setMethods.keySet().contains(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.keySet().contains(propertyName);}public String findPropertyName(String name) {return caseInsensitivePropertyMap.get(name.toUpperCase(Locale.ENGLISH));}/** Gets an instance of ClassInfo for the specified class.* 得到某个类的反射器,是静态方法,而且要缓存,又要多线程,所以REFLECTOR_MAP是一个ConcurrentHashMap** @param clazz The class for which to lookup the method cache.* @return The method cache for the class*/public static Reflector forClass(Class<?> clazz) {if (classCacheEnabled) {// synchronized (clazz) removed see issue #461// 对于每个类来说,我们假设它是不会变的,这样可以考虑将这个类的信息(构造函数,getter,setter,字段)加入缓存,以提高速度Reflector cached = REFLECTOR_MAP.get(clazz);if (cached == null) {cached = new Reflector(clazz);REFLECTOR_MAP.put(clazz, cached);}return cached;} else {return new Reflector(clazz);}}public static void setClassCacheEnabled(boolean classCacheEnabled) {Reflector.classCacheEnabled = classCacheEnabled;}public static boolean isClassCacheEnabled() {return classCacheEnabled;}}

3.3 元类

MetaClass:元类,因为反射器都是基础的操作,为了方便使用对反射器的进一步封装,获取反射器里的容器数据,元类里提供反射器缓存,这样不用相同的类每次调用都解析处理了,也是补充丰富了反射器基础的操作,相当于解构一个对象包装一个元类,而这些元类,包装器,对象工厂再组合成一个元对象,相当于说这些元类和元对象都是对我们需要操作的原对象解耦后的封装。有了这样的操作,就可以让我们处理每一个属性或者方法了。

/*** @description 元类* Reflector 反射器类提供的是最基础的核心功能,很多方法也都是私有的,为了更加方便的使用,* 还需要做一层元类的包装。在元类 MetaClass 提供必要的创建反射器以及使用反射器获取* get/set 的 Invoker 反射方法* */
public class MetaClass {// 反射器,用于解析和存储目标类中的元信息private Reflector reflector;// Reflector.forClass获取当前类的反射器private MetaClass(Class<?> type) {this.reflector = Reflector.forClass(type);}public static MetaClass forClass(Class<?> type) {return new MetaClass(type);}public static boolean isClassCacheEnabled() {return Reflector.isClassCacheEnabled();}public static void setClassCacheEnabled(boolean classCacheEnabled) {Reflector.setClassCacheEnabled(classCacheEnabled);}public MetaClass metaClassForProperty(String name) {Class<?> propType = reflector.getGetterType(name);return MetaClass.forClass(propType);}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);}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 _method = MethodInvoker.class.getDeclaredField("method");_method.setAccessible(true);Method method = (Method) _method.get(invoker);return method.getGenericReturnType();} else if (invoker instanceof GetFieldInvoker) {Field _field = GetFieldInvoker.class.getDeclaredField("field");_field.setAccessible(true);Field field = (Field) _field.get(invoker);return field.getGenericType();}} catch (NoSuchFieldException | IllegalAccessException 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();}}

3.4 对象包装器

ObjectWapper:对象包装器接口,定义对象基本操作,获取对象值、设置对象值、查找属性、获取get方法、获取set方法、属性类型、添加属性、设置属性等等...对象包装器主要是定义了更加明确的使用方法。

package df.middleware.mybatis.reflection.wrapper

/*** @description 对象包装器* 是对对象的包装的接口,抽象了对象的字段信息、 getter| setter 方法、和上面三个成员的数据类型,* 它定义了一系列查询对象属性信息的方法,以及更新属性的方法 。添加属性方法*/
public interface ObjectWrapper {// getObject get(PropertyTokenizer prop);// setvoid set(PropertyTokenizer prop, Object value);// 查找属性String findProperty(String name, boolean useCamelCaseMapping);// 取得getter的名字列表String[] getGetterNames();// 取得setter的名字列表String[] getSetterNames();//取得setter的类型Class<?> getSetterType(String name);// 取得getter的类型Class<?> getGetterType(String name);// 是否有指定的setterboolean hasSetter(String name);// 是否有指定的getterboolean hasGetter(String name);// 实例化属性MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory);// 是否是集合boolean isCollection();// 添加属性void add(Object element);// 添加属性<E> void addAll(List<E> element);}

BaseWrapper:基础对象包装器,抽象类,实现ObjectWapper,主要是抽取公共代码,方便由各子类对象包装器使用,如处理集合则可调用基础对象包装器方法即可,此类主要处理解析集合、获取集合、设置集合中的值

/*** @description 对象包装器抽象基类,提供一些工具方法* BaseWrapper 抽象类 定义了集合的相关操作。* 1.解析集合* 2.获取集合中的值* 3.设置集合中的值* */
public abstract class BaseWrapper implements ObjectWrapper {protected static final Object[] NO_ARGUMENTS = new Object[0];protected MetaObject metaObject;protected BaseWrapper(MetaObject metaObject) {this.metaObject = metaObject;}/*** 解析集合*/protected Object resolveCollection(PropertyTokenizer prop, Object object) {if ("".equals(prop.getName())) {return object;} else {return metaObject.getValue(prop.getName());}}/*** 取集合的值* 中括号有2个意思,一个是Map,一个是List或数组*/protected Object getCollectionValue(PropertyTokenizer prop, Object collection) {if (collection instanceof Map) {//map['name']return ((Map) collection).get(prop.getIndex());} else {int i = Integer.parseInt(prop.getIndex());if (collection instanceof List) {//list[0]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 RuntimeException("The '" + prop.getName() + "' property of " + collection + " is not a List or Array.");}}}/*** 设集合的值* 中括号有2个意思,一个是Map,一个是List或数组*/protected void setCollectionValue(PropertyTokenizer prop, Object collection, Object value) {if (collection instanceof Map) {((Map) collection).put(prop.getIndex(), value);} else {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 RuntimeException("The '" + prop.getName() + "' property of " + collection + " is not a List or Array.");}}}
}

MapWrapper:Map对象包装器,是对Map对象的封装,继承了 BaseWrapper,构造传入map类型对象,获取设置值等等也以map方式即可。

/*** @description Map 包装器* MapWrapper 是 Map 集合对象的封装。
*/
public class MapWrapper extends BaseWrapper {// 原来的对象private Map<String, Object> map;public MapWrapper(MetaObject metaObject, Map<String, Object> map) {super(metaObject);this.map = map;}// get,set是允许的,@Overridepublic Object get(PropertyTokenizer prop) {//如果有index,说明是集合,那就要分解集合,调用的是BaseWrapper.resolveCollection 和 getCollectionValueif (prop.getIndex() != null) {Object collection = resolveCollection(prop, map);return getCollectionValue(prop, collection);} else {return map.get(prop.getName());}}@Overridepublic 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);}}@Overridepublic String findProperty(String name, boolean useCamelCaseMapping) {return name;}@Overridepublic String[] getGetterNames() {return map.keySet().toArray(new String[map.keySet().size()]);}@Overridepublic String[] getSetterNames() {return map.keySet().toArray(new String[map.keySet().size()]);}@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 Object.class;} else {return metaValue.getSetterType(prop.getChildren());}} else {if (map.get(name) != null) {return map.get(name).getClass();} else {return Object.class;}}}@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 Object.class;} else {return metaValue.getGetterType(prop.getChildren());}} else {if (map.get(name) != null) {return map.get(name).getClass();} else {return Object.class;}}}@Overridepublic boolean hasSetter(String name) {return true;}@Overridepublic 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());}}@Overridepublic MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) {HashMap<String, Object> map = new HashMap<String, Object>();set(prop, map);return MetaObject.forObject(map, metaObject.getObjectFactory(), metaObject.getObjectWrapperFactory());}@Overridepublic boolean isCollection() {return false;}@Overridepublic void add(Object element) {throw new UnsupportedOperationException();}@Overridepublic <E> void addAll(List<E> element) {throw new UnsupportedOperationException();}
}

CollectionWrapper:Collection对象包装器,实现ObjectWapper接口,除了添加集合、暂不支持其他操作,抛出异常即可。

/*** @author 小傅哥,微信:fustack* @description Collection 包装器*/
public class CollectionWrapper implements ObjectWrapper{// 原来的对象private Collection<Object> object;public CollectionWrapper(MetaObject metaObject, Collection<Object> object) {this.object = object;}// get,set都是不允许的,只能添加元素@Overridepublic Object get(PropertyTokenizer prop) {throw new UnsupportedOperationException();}@Overridepublic void set(PropertyTokenizer prop, Object value) {throw new UnsupportedOperationException();}@Overridepublic String findProperty(String name, boolean useCamelCaseMapping) {throw new UnsupportedOperationException();}@Overridepublic String[] getGetterNames() {throw new UnsupportedOperationException();}@Overridepublic String[] getSetterNames() {throw new UnsupportedOperationException();}@Overridepublic Class<?> getSetterType(String name) {throw new UnsupportedOperationException();}@Overridepublic Class<?> getGetterType(String name) {throw new UnsupportedOperationException();}@Overridepublic boolean hasSetter(String name) {throw new UnsupportedOperationException();}@Overridepublic boolean hasGetter(String name) {throw new UnsupportedOperationException();}@Overridepublic MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) {throw new UnsupportedOperationException();}@Overridepublic boolean isCollection() {return true;}@Overridepublic void add(Object element) {object.add(element);}@Overridepublic <E> void addAll(List<E> element) {object.addAll(element);}}

BeanWrapper:原始对象的封装,自定义对象封装,继承BaseWapper,这个是重点,因为是Bean对象,我们需要解析类里属性以及get,set方法,此时我们需要通过元类进入反射器进行解析,所以BeanWrapper依赖MetaClass

/*** @description Bean 包装器* BeanWrapper 是原始对象的封装*/
public class BeanWrapper extends BaseWrapper {// 原来的对象private Object object;// 元类private MetaClass metaClass;public BeanWrapper(MetaObject metaObject, Object object) {super(metaObject);this.object = object;// 通过元类获取反射器 1个入口this.metaClass = MetaClass.forClass(object.getClass());}@Overridepublic Object get(PropertyTokenizer prop) {// 如果有index(有中括号),说明是集合,那就要解析集合,调用的是 BaseWrapper.resolveCollection 和 getCollectionValueif (prop.getIndex() != null) {Object collection = resolveCollection(prop, object);return getCollectionValue(prop, collection);} else {// 否则,getBeanPropertyreturn getBeanProperty(prop, object);}}@Overridepublic void set(PropertyTokenizer prop, Object value) {// 如果有index,说明是集合,那就要解析集合,调用的是BaseWrapper.resolveCollection 和 setCollectionValueif (prop.getIndex() != null) {Object collection = resolveCollection(prop, object);setCollectionValue(prop, collection, value);} else {// 否则,setBeanPropertysetBeanProperty(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());set(prop, newObject);} catch (Exception e) {throw new RuntimeException("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;}@Overridepublic boolean isCollection() {return false;}@Overridepublic void add(Object element) {throw new UnsupportedOperationException();}@Overridepublic <E> void addAll(List<E> list) {throw new UnsupportedOperationException();}private Object getBeanProperty(PropertyTokenizer prop, Object object) {try {// 得到getter方法,然后调用Invoker method = metaClass.getGetInvoker(prop.getName());return method.invoke(object, NO_ARGUMENTS);} catch (RuntimeException e) {throw e;} catch (Throwable t) {throw new RuntimeException("Could not get property '" + prop.getName() + "' from " + object.getClass() + ".  Cause: " + t.toString(), t);}}private void setBeanProperty(PropertyTokenizer prop, Object object, Object value) {try {// 得到setter方法,然后调用Invoker method = metaClass.getSetInvoker(prop.getName());Object[] params = {value};method.invoke(object, params);} catch (Throwable t) {throw new RuntimeException("Could not set property '" + prop.getName() + "' of '" + object.getClass() + "' with value '" + value + "' Cause: " + t.toString(), t);}}
}

3.5 元对象

有了元类,反射器,对象包装器,最后我们统一一个元对象进行封装,对外统一调用方式,组成一个完整的元对象操作类。通过构造方法创建不同的对象包装器,获取此类中方法则自然调度到不同的wapper包装器里,实现整条链路

/*** @description 元对象* */
public class MetaObject {// 原对象private Object originalObject;/*** 封装过的 Object 对象*/// 对象包装器private ObjectWrapper objectWrapper;// 对象工厂private ObjectFactory objectFactory;// 对象包装工厂private ObjectWrapperFactory objectWrapperFactory;// 赋值为不同的包装器private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory) {this.originalObject = object;this.objectFactory = objectFactory;this.objectWrapperFactory = objectWrapperFactory;if (object instanceof ObjectWrapper) {// 如果对象本身已经是ObjectWrapper型,则直接赋给objectWrapperthis.objectWrapper = (ObjectWrapper) object;} else if (objectWrapperFactory.hasWrapperFor(object)) {// 如果有包装器,调用ObjectWrapperFactory.getWrapperForthis.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);} else if (object instanceof Map) {// 如果是Map型,返回MapWrapperthis.objectWrapper = new MapWrapper(this, (Map) object);} else if (object instanceof Collection) {// 如果是Collection型,返回CollectionWrapperthis.objectWrapper = new CollectionWrapper(this, (Collection) object);} else {// 除此以外,返回BeanWrapperthis.objectWrapper = new BeanWrapper(this, object);}}/*** 创建 MetaObject 对象** @param object 原始 Object 对象* @param objectFactory* @param objectWrapperFactory* @return MetaObject 对象*/public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory) {if (object == null) {// 处理一下null,将null包装起来return SystemMetaObject.NULL_META_OBJECT;} else {return new MetaObject(object, objectFactory, objectWrapperFactory);}}public ObjectFactory getObjectFactory() {return objectFactory;}public ObjectWrapperFactory getObjectWrapperFactory() {return objectWrapperFactory;}public Object getOriginalObject() {return originalObject;}/* --------以下方法都是委派给 ObjectWrapper------ */// 查找属性,相当于又封装了一层public String findProperty(String propName, boolean useCamelCaseMapping) {return objectWrapper.findProperty(propName, useCamelCaseMapping);}/*** 获取get方法属性名称和get方法去掉get后边的属性名称* getIds(){return id;} --> (id、ids)* @return*/// 取得getter的名字列表public String[] getGetterNames() {return objectWrapper.getGetterNames();}/*** 获取set方法属性名称和set方法去掉set后边的属性名称* setIds(){return id;} --> (id、ids)* @return*/// 取得setter的名字列表public String[] getSetterNames() {return objectWrapper.getSetterNames();}/*** 获取set方法后边属性的类型* @param name 这个name 要和setXXX方法中的XXX相同才能获取到,否则抛异常* @return*/// 取得setter的类型列表public Class<?> getSetterType(String name) {return objectWrapper.getSetterType(name);}/*** 获取get方法后边属性的类型* @param name 这个name,要个getXXX方法中的XXX相同才能获取到,否则抛异常* @return*/// 取得getter的类型列表public Class<?> getGetterType(String name) {return objectWrapper.getGetterType(name);}/*** 判断name是否是setXXX()方法中的XXX* @param name* @return*///是否有指定的setterpublic boolean hasSetter(String name) {return objectWrapper.hasSetter(name);}/*** 判断name是否是getXXX()方法中的XXX* @param name* @return*/// 是否有指定的getterpublic boolean hasGetter(String name) {return objectWrapper.hasGetter(name);}/*** 获取对象属性值,可以递归获取* @param name* @return*/// 取得值// 如 班级[0].学生.成绩public Object getValue(String name) {// 创建 PropertyTokenizer 对象,对 name 分词PropertyTokenizer prop = new PropertyTokenizer(name);// 有子表达式if (prop.hasNext()) {// 创建 MetaObject 对象,递归调用MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());// 递归判断子表达式 children ,获取值,metaValue == null,则返回nullif (metaValue == SystemMetaObject.NULL_META_OBJECT) {// 如果上层就是null了,那就结束,返回nullreturn null;} else {// 否则继续看下一层,递归调用getValuereturn metaValue.getValue(prop.getChildren());}} else {// 无子表达式,取值return objectWrapper.get(prop);}}/*** 给对象属性设置值,可以递归设置,基本类型,数组,对象,都可以自动创建* 但是ArrayList和数组需要手动创建* List必须创建对象,添加进list* @param name* @param value*/// 如 班级[0].学生.成绩public void setValue(String name, Object value) {// 创建 PropertyTokenizer 对象,对 name 分词PropertyTokenizer prop = new PropertyTokenizer(name);// 有子表达式if (prop.hasNext()) {// 创建 MetaObject 对象MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());// 递归判断子表达式 children ,设置值if (metaValue == SystemMetaObject.NULL_META_OBJECT) {if (value == null && prop.getChildren() != null) {// don't instantiate child path if value is null// 如果上层就是 null 了,还得看有没有儿子,没有那就结束return;} else {// 创建值// 否则还得 new 一个,委派给 ObjectWrapper.instantiatePropertyValuemetaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory);}}// 递归调用setValuemetaValue.setValue(prop.getChildren(), value);} else {// 到了最后一层了,所以委派给 ObjectWrapper.setobjectWrapper.set(prop, value);}}// 为属性生成元对象public MetaObject metaObjectForProperty(String name) {// 实际是递归调用Object value = getValue(name);return MetaObject.forObject(value, objectFactory, objectWrapperFactory);}public ObjectWrapper getObjectWrapper() {return objectWrapper;}// 是否是集合public boolean isCollection() {return objectWrapper.isCollection();}// 添加属性public void add(Object element) {objectWrapper.add(element);}// 添加属性public <E> void addAll(List<E> list) {objectWrapper.addAll(list);}}

3.6 系统元对象

SystemMetaObject:可通过此类获取元对象

/*** @description 一些系统级别的元对象*/
public class SystemMetaObject {public static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();public static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();public static final MetaObject NULL_META_OBJECT = MetaObject.forObject(NullObject.class, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);private SystemMetaObject() {// Prevent Instantiation of Static Class}/*** 空对象*/private static class NullObject {}public static MetaObject forObject(Object object) {return MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);}
}

3.7 对象工厂

ObjectFactory:对象工厂接口,创建对象处理

/*** @description 对象工厂接口
*/
public interface ObjectFactory {/*** Sets configuration properties.* 设置属性* @param properties configuration properties*/void setProperties(Properties properties);/*** Creates a new object with default constructor.* 生产对象* @param type Object type* @return <T>*/<T> T create(Class<T> type);/*** Creates a new object with the specified constructor and params.* 生产对象,使用明确的构造函数和构造函数参数* @param type Object type* @param constructorArgTypes Constructor argument types* @param constructorArgs Constructor argument values* @return <T>*/<T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);/*** Returns true if this object can have a set of other objects.* It's main purpose is to support non-java.util.Collection objects like Scala collections.* 返回这个对象是否是集合,为了支持 Scala collections** @since 3.1.0* @param type Object type* @return whether it is a collection or not*/<T> boolean isCollection(Class<T> type);
}

DefaultObjectFactory:默认对象工厂,实现对象工厂,对象实例化操作,在对象包装器中复杂场景有子集合对象时进行对象生成操作。

/*** @description 默认对象工厂,所有的对象都有工厂来生成
*/
public class DefaultObjectFactory implements ObjectFactory, Serializable {private static final long serialVersionUID = -8855120656740914948L;@Overridepublic void setProperties(Properties properties) {// no props for default 默认无属性可设置}@Overridepublic <T> T create(Class<T> type) {return create(type, null, null);}@SuppressWarnings("unchecked")@Overridepublic <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {// 1. 解析接口Class<?> classToCreate = resolveInterface(type);// 2. 类实例化return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);}private <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {try {Constructor<T> constructor;//如果没有传入constructor,调用空构造函数,核心是调用Constructor.newInstanceif (constructorArgTypes == null || constructorArgs == null) {// 能够得到私有的和公有的构造方法constructor = type.getDeclaredConstructor();if (!constructor.isAccessible()) {// 方法获得的构造器需要先设置可访问,再实例化对象constructor.setAccessible(true);}return constructor.newInstance();}// 如果传入constructor,调用传入的构造函数,核心是调用Constructor.newInstanceconstructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[constructorArgTypes.size()]));if (!constructor.isAccessible()) {constructor.setAccessible(true);}return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));} catch (Exception e) {// 如果出错,包装一下,重新抛出自己的异常StringBuilder argTypes = new StringBuilder();if (constructorArgTypes != null) {for (Class<?> argType : constructorArgTypes) {argTypes.append(argType.getSimpleName());argTypes.append(",");}}StringBuilder argValues = new StringBuilder();if (constructorArgs != null) {for (Object argValue : constructorArgs) {argValues.append(argValue);argValues.append(",");}}throw new RuntimeException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + e, e);}}@Overridepublic <T> boolean isCollection(Class<T> type) {return Collection.class.isAssignableFrom(type);}/*** 解析接口,将 interface 转换为实际的 class 类*/protected Class<?> resolveInterface(Class<?> type) {Class<?> classToCreate;if (type == List.class || type == Collection.class || type == Iterable.class) {// List|Collection|Iterable-->ArrayListclassToCreate = ArrayList.class;} else if (type == Map.class) {// Map->HashMapclassToCreate = HashMap.class;} else if (type == SortedSet.class) {// SortedSet->TreeSetclassToCreate = TreeSet.class;} else if (type == Set.class) {// Set->HashSetclassToCreate = HashSet.class;} else {// 除此以外,就用原来的类型classToCreate = type;}return classToCreate;}
}

3.8 属性命名器

/*** @description 属性命名器* namer 命名者*/
public class PropertyNamer {private PropertyNamer() {}/*** 方法转换为属性*/public static String methodToProperty(String name) {if (name.startsWith("is")) {name = name.substring(2);} else if (name.startsWith("get") || name.startsWith("set")) {name = name.substring(3);} else {throw new RuntimeException("Error parsing property name '" + name + "'.  Didn't start with 'is', 'get' or 'set'.");}/** 如果只有1个字母,转换为小写* 如果大于1个字母,第二个字母非大写,转换为小写*/if (name.length() == 1 || (name.length() > 1 && !Character.isUpperCase(name.charAt(1)))) {name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1);}return name;}/*** 开头判断是否是get/set/is的方法*/public static boolean isProperty(String name) {return name.startsWith("get") || name.startsWith("set") || name.startsWith("is");}/*** 是否为 getter*/public static boolean isGetter(String name) {return name.startsWith("get") || name.startsWith("is");}/*** 是否为 setter*/public static boolean isSetter(String name) {return name.startsWith("set");}
}

3.9 属性分解器

PropertyTokenizer:此类贯穿整个工具使用,主要是解析属性是不是只是简单属性还是复杂属性,如果有集合,需要解析下标,子集合名称等操作

/*** @description 属性分解标记* 可以解析处理简单属性以及list集合Map等等的数据* 亮点:可迭代,可以看看*/
public class PropertyTokenizer implements Iterable<PropertyTokenizer>, Iterator<PropertyTokenizer> {// 例子:班级[0].学生.成绩// 班级,父表达式private String name;// 班级[0],带索引的表达式,由父表达式和下标组成private String indexedName;// 0 ,下标,该属性只对字段类型为map|list|array类型的字段有效,对于list和array类型的字段,index保存的是下标。private String index;// 学生.成绩,,子表达式:该属性只对嵌套表达式有效private String children;public PropertyTokenizer(String fullname) {// 班级[0].学生.成绩// 找这个点 .// 解析出parent表达式和children表达式int delim = fullname.indexOf('.');if (delim > -1) {name = fullname.substring(0, delim);//截取到parent表达式children = fullname.substring(delim + 1);//截取到children表达式} else {// 找不到.的话,取全部部分name = fullname;//fullname 即为parent表达式children = null;//无children}indexedName = name;// 把中括号里的数字给解析出来delim = name.indexOf('[');if (delim > -1) {//如果有下标index = name.substring(delim + 1, name.length() - 1);保存下标到indexname = name.substring(0, delim);//3.截取出field name,}}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另外一个实例@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.");}@Overridepublic Iterator<PropertyTokenizer> iterator() {return this;}
}

3.10 使用反射器数据源属性设置

那我们先来把UnpooledDataSourceFactory的数据源属性进行设置

public class UnpooledDataSourceFactory implements DataSourceFactory {protected DataSource dataSource;public UnpooledDataSourceFactory() {this.dataSource = new UnpooledDataSource();}protected Properties pros;@Overridepublic void setProperties(Properties props) {MetaObject metaObject = SystemMetaObject.forObject(dataSource);for (Object key : props.keySet()) {String propertyName = (String) key;if (metaObject.hasSetter(propertyName)) {String value = (String) props.get(propertyName);Object convertedValue = convertValue(metaObject, propertyName, value);metaObject.setValue(propertyName, convertedValue);}}}@Overridepublic DataSource getDataSource() {return dataSource;}/*** 根据setter的类型,将配置文件中的值强转成相应的类型*/private Object convertValue(MetaObject metaObject, String propertyName, String value) {Object convertedValue = value;Class<?> targetType = metaObject.getSetterType(propertyName);if (targetType == Integer.class || targetType == int.class) {convertedValue = Integer.valueOf(value);} else if (targetType == Long.class || targetType == long.class) {convertedValue = Long.valueOf(value);} else if (targetType == Boolean.class || targetType == boolean.class) {convertedValue = Boolean.valueOf(value);}return convertedValue;}
}

到此我们所有的类都介绍完毕了,我们用单元测试可以测试下,测试准备和上几节一样,可直接运行debug看下通过反射将DataSource的驱动 ,用户名,密码等反射设置进来

完事,本节所有的代码都已完全展现,大家想要源码可以去bugStack冲动栈,小傅哥那里

相关文章:

手敲Mybatis(六)-反射工具天花板

历时漫长的岁月&#xff0c;终于鼓起勇气继续研究Mybatis的反射工具类们&#xff0c;简直就是把反射玩出花&#xff0c;但是理解起来还是很有难度的&#xff0c;涉及的内容代码也颇多&#xff0c;所以花费时间也比较浩大&#xff0c;不过当了解套路每个类的功能也好&#xff0c…...

内含18禁~~关于自学\跳槽\转行做网络安全行业的一些建议

作者&#xff1a;Eason_LYC 悲观者预言失败&#xff0c;十言九中。 乐观者创造奇迹&#xff0c;一次即可。 一个人的价值&#xff0c;在于他所拥有的。所以可以不学无术&#xff0c;但不能一无所有&#xff01; 技术领域&#xff1a;WEB安全、网络攻防 关注WEB安全、网络攻防。…...

春分策划×运维老王主讲:CMDB数据运营精准化公开课启动报名啦!

『CMDB数据运营精准化』 公开直播课 要来了&#xff01; &#x1f446;扫描海报二维码&#xff0c;预约直播 CMDB似乎是运维中永恒的老话题。 提到CMDB很多人都是又爱又恨&#xff0c;爱的是它给我们提供了一个美好的未来&#xff0c;有了CMDB我们可以解决诸多运维中的难题。…...

制作INCA和CANape通用的A2L

文章目录 前言制作A2LA2ML定义MOD_COMMON定义MOD_PAR定义MEMORY_SEGMENTTransportLayer定义PROTOCOL_LAYERDAQ总结前言 由于INCA和CANape是两个不同的公司对XCP协议的实现,所以A2L中也会有不一样的地方,但是在标定时若每次都用两个A2L,是非常不方便的,本文介绍如何设计A2L…...

Python人脸识别

#头文件&#xff1a;import cv2 as cvimport numpy as npimport osfrom PIL import Imageimport xlsxwriterimport psutilimport time#人脸录入def get_image_name(name):name_map {f.split(.)[1]:int(f.split(.)[0]) for f in os.listdir("./picture")}if not name…...

我用Python写了一个下载网站所有内容的软件,可见即可下,室友表示非常好用

Python 写一个下载网站内容的GUI工具&#xff0c;所有内容都能下载&#xff0c;真的太方便了&#xff01;前言本次要实现的功能效果展示代码实战获取数据GUI部分最后前言 哈喽大家好&#xff0c;我是轻松。 今天我们分享一个用Python写下载视频弹幕评论的代码。 之前自游写了…...

【M365运维】扩充OneDrive存储空间

【问题】E3,E5等订阅许可下&#xff0c;默认的OneDrive存储空间为 1TB&#xff0c;满了之后该如何扩充&#xff1f;【解决】1.运行Powershell2. 链接到Sharepoint Online: Connect-SPOSerivce -url https://<这里通常是公司名>-admin.sharepoint.com3. 定义三个扩充空间时…...

hashcat(爆破工具,支持GPU,精)

目录 简介 分类 参数 -m hash的类型 -a 攻击方式 掩码 使用方法 字典破解 简介 虽然John the R...

【机器学习】什么是监督学习、半监督学习、无监督学习、自监督学习以及弱监督学习

监督学习&#xff08;Supervised Learning&#xff09;&#xff1a;利用大量的标注数据来训练模型&#xff0c;模型最终学习到输入与输出标签之间的相关性。半监督学习&#xff08;Semi- supervised Learning&#xff09;&#xff1a;利用少量有标签数据和大量无标签数据来训练…...

HashiCorp packer 制作AWS AMI镜像示例

准备工作 验证AWS 可以先手动启动一个EC2实例验证自己创建的VPC, subnet, internet gateway 和routetable等, 确保实例创建后不会出现连接不上的情况. 可以按照下面的链接配置避免连接超时 https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/TroubleshootingInstan…...

【java基础】根据泛型动态构造jackson的TypeReference(json反序列化为带泛型的类的对象)

根据泛型动态构造jackson的TypeReference引出问题使用TypeReference反序列化的例子根据泛型动态构造TypeReference带泛型的类如何表示&#xff1f;完成HttpClient的实现引出问题 将json字符串反序列化为带泛型的类的对象怎么操作&#xff1f;怎么根据TypeReference<List<…...

为什么VMware会给我多创建了两个网络呢?Windows和Linux为什么可以彼此ping的通呢

为什么VMware会给我多创建了两个网络呢&#xff1f;Windows和Linux为什么可以彼此ping的通呢 文章目录为什么VMware会给我多创建了两个网络呢&#xff1f;Windows和Linux为什么可以彼此ping的通呢桥接模式ANT模式&#xff08;VMnet8&#xff09;仅主机模式&#xff08;VMnet1&a…...

服务器带宽承载多少人同时访问计算方法-浏览器中查看当前网页所有资源数据大小-客服系统高并发承载人数【唯一客服】...

浏览器中怎么查看当前网页所有资源的数据大小 在开发者工具的“网络”选项卡中&#xff0c;可以看到所有请求和响应的详细信息&#xff0c;包括每个资源的大小。如果需要查看网页所有资源的总大小&#xff0c;可以按照以下步骤操作&#xff1a; 打开要查看的网页。打开开发者工…...

给新手----编译VSOMEIP保姆级别教程

前言&#xff1a;当你学习了SOMEIP理论基础后&#xff0c;一定很希望上手实操一波吧&#xff0c;本文档以SOMEIP协议里比较成熟的VSOMEIP开源框架为例&#xff0c;带你从0到1实现开源框架的下载到上手&#xff0c;坐稳啦&#xff0c;开车&#xff01;&#xff01;&#xff01;&…...

MarkDown设置上下标

上标&#xff1a;$a^{2-5}$ 下标&#xff1a;$a_{n-1}$显示&#xff1a;结果 上标&#xff1a;a2−5a^{2-5}a2−5 下标&#xff1a;an−1a_{n-1}an−1​ 如果上下标中需要多个显示&#xff0c;需要用{}括起来&#xff0c;否则就像下面一样 上标&#xff1a;$a^2-5$ 下标&…...

Python批量爬取游戏卡牌信息

文章目录前言一、需求二、分析三、处理四、运行结果前言 本系列文章来源于真实的需求本系列文章你来提我来做本系列文章仅供学习参考阅读人群&#xff1a;有Python基础、Scrapy框架基础 一、需求 全站爬取游戏卡牌信息 二、分析 查看网页源代码&#xff0c;图片资源是否存在…...

什么是PCB走线的3W原则

在设计PCB的时候我们会经常说到3W原则&#xff0c; 它指的是两个PCB走线它们的中心间距不小于3倍线宽&#xff0c;这个W就是PCB走线的宽度。这样做的目的主要是为了减小走线1和走线2之间的串扰&#xff0c;一般对于时钟信号&#xff0c;复位信号等一些关键信号需要遵循3W原则。…...

计算机网络面试总结

计算机网络 1.计算机网络 2.计算机网络拓扑结构 3.计算机网络覆盖 4.时延 5.交换技术 6.单工、半双工、全双工 7.OSI模型 8.TCP/IP模型 9.物理层有哪些设备 10.数据链路层介质访问控制 11.数据链路层有哪些设备 12.数据链路层流量控制 13.数据链路层的三个基本问题和解决方法 1…...

VsCode SSH远程连接服务器【内网穿透公网连接】

文章目录1.前言2.VS code的安装和设置2.1 VS code的下载安装2.2 OpenSSH的启用2.3 为VS code配置ssh2.4 局域网内测试VS code的ssh连接2.5 Cpolar下载安装3.Cpolar端口设置3.1 Cpolar云端设置3.2 Cpolar本地设置4.公网访问测试5.结语1.前言 记得笔者小时候看电视&#xff0c;看…...

十八、动画与canvas

1.RequestAnimationFrame 早期定时动画 setTimeout和setInterval不能保证时间精度&#xff0c;第二个参数只能保证何时将代码添加到浏览器的任务队列 requestAnimationFrame(cb)的cb在浏览器重绘屏幕前调用 function updateProgress(){const div document.getElementById(d…...

自动化测试学习-Day4-selenium的安装和8种定位方法

哈喽&#xff0c;大家好&#xff01; 本人21年毕业&#xff0c;软件工程专业&#xff0c;毕业后一直从事金融行业的软件测试。 希望大家一起见证一名卑微测试的成长之路。 目录 一、环境准备 1.浏览器下载 2.浏览器驱动下载 3.下载selenium 二、Selenium定位元素的8种方法…...

【Kubernetes】第二十五篇 - 布署 nodejs 后端项目(下)

一&#xff0c;前言 上一篇&#xff0c;介绍了部署后端项目之前&#xff0c;需要的准备的相关配置信息&#xff1b; 本篇&#xff0c;创建 Deployment、Service 完成后端项目布署&#xff1b; 二&#xff0c;解决 jenkins 安全问题 构建 docker 镜像之后&#xff0c;登录 do…...

贪心算法之区间问题总结

一、跳跃游戏跳跃游戏类的问题&#xff0c;不关心每一步怎么跳&#xff0c;只需要关心最大覆盖范围这里注意i是在当前最大可覆盖范围内遍历&#xff0c;如{2,1,0,1}&#xff0c;就是在0~2范围内遍历&#xff0c;千万不能0~numsSize-1范围内遍历&#xff01;&#xff01;&#x…...

无线WiFi安全渗透与攻防(七)之WIFI07-WEP-wifite自动化渗透WEP加密

WIFI07-WEP-wifite自动化渗透WEP加密 1.wifite介绍 wifite是一款自动化wep、wpa以及wps破解工具&#xff0c;不支持windows和osx。wifite的特点是可以同时攻击多个采用wep和wpa加密的网络。wifite只需简单的配置即可自动化运行&#xff0c;期间无需人工干预。 目前支持任何li…...

震撼,支持多模态模型的ChatGPT 4.0发布了

最近几个月&#xff0c;互联网和科技圈几乎ChatGPT刷屏了&#xff0c;各种关于ChatGPT的概念和应用的帖子也是围绕在周围。当去年年底ChatGPT发布的那几天&#xff0c;ChatGPT确实震撼到了所有人&#xff0c;原来AI还可以这么玩&#xff0c;并且对国内的那些所谓的人工智能公司…...

IDEA常用插件列表

一 背景 IDEA常用插件列表&#xff0c;用来提供工作效率。你都安装了吗 IntelliJ IDEA 默认安装并提供了非常多的工具&#xff0c;比如 Maven Integration、Markdown support、SSH Remote Run 等。其中有很多好用&#xff0c;但是不为人知的工具。 二 插件列表 阿里代码规约…...

比df更好用的命令!

大家好&#xff0c;我是良许。 对于分析磁盘使用情况&#xff0c;有两个非常好用的命令&#xff1a;du 和 df 。简单来说&#xff0c;这两个命令的作用是这样的&#xff1a; du 命令&#xff1a;它是英文单词 disk usage 的简写&#xff0c;主要用于查看文件与目录占用多少磁…...

【Git使用学习】记录学习过程(1)

安装就省略了&#xff0c;安装结果如下。 Git Bash&#xff1a;这是一个模拟Linux环境的命令行工具&#xff0c;可以使用Git的所有功能。Git GUI&#xff1a;这是一个图形化界面的工具&#xff0c;可以方便地执行Git的常用操作。Git CMD&#xff1a;这是一个Windows命令行工具&…...

K_A18_001 基于STM32等单片机采集MQ2传感参数串口与OLED0.96双显示

K_A18_001 基于STM32等单片机采集MQ2传感参数串口与OLED0.96双显示一、资源说明二、基本参数参数引脚说明三、驱动说明IIC地址/采集通道选择/时序对应程序:四、部分代码说明1、接线引脚定义1.1、STC89C52RCMQ2传感参模块1.2、STM32F103C8T6MQ2传感参模块五、基础知识学习与相关…...

【云原生·Docker】常用命令

目录 &#x1f341;1、管理命令 &#x1f341;2、帮助命令 &#x1f341;3、镜像命令 &#x1f341;4、容器命令 &#x1f342;4.1.查看容器 &#x1f342;4.2.创建容器 &#x1f342;4.3.删除容器 &#x1f342;4.4.拷贝文件 &#x1f342;4.5.查看容器IP &#x1f341;5、部署…...