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

手敲Mybatis-反射工具天花板

历时漫长的岁月,终于鼓起勇气继续研究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…...

Java -数据结构,【优先级队列 / 堆】

一、二叉树的顺序存储 在前面我们已经讲了二叉树的链式存储&#xff0c;就是一棵树的左孩子和右孩子 而现在讲的是&#xff1a;顺序存储一棵二叉树。 1.1、存储方式 使用数组保存二叉树结构&#xff0c;方式即将二叉树用层序遍历方式放入数组中。 一般只适合表示完全二叉树&a…...

Python+Qt指纹录入识别考勤系统

PythonQt指纹录入识别考勤系统如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01;前言这篇博客针对<<PythonQt指纹录入识别考勤系统>>编写代码&#xff0c;代码整洁&#xff0c;规则&#xff0c;易读。 学…...

K_A14_004 基于STM32等单片机驱动旋转角度传感器模块 串口与OLED0.96双显示

K_A14_004 基于STM32等单片机驱动旋转角度传感器模块 串口与OLED0.96双显示一、资源说明二、基本参数参数引脚说明三、驱动说明IIC地址/采集通道选择/时序对应程序:四、部分代码说明1、接线引脚定义1.1、STC89C52RC旋转角度传感器模块1.2、STM32F103C8T6旋转角度传感器模块五、…...

2023年全国最新机动车签字授权人精选真题及答案12

百分百题库提供机动车签字授权人考试试题、机动车签字授权人考试预测题、机动车签字授权人考试真题、机动车签字授权人证考试题库等&#xff0c;提供在线做题刷题&#xff0c;在线模拟考试&#xff0c;助你考试轻松过关。 11.注册登记前所有机动车都应进行安全技术检验。 答案…...

Linux小黑板(10):信号

我们写在linux系统环境下写一个程序&#xff0c;唔&#xff0c;"它的功能是每隔1s向屏幕打印hello world。"这时&#xff0c;我们在键盘上按出"Ctrl C"后,进程会发生什么&#xff1f;&#xff1f;我们清晰地看到&#xff0c;进程已经在我们按出"Ctrl…...

GO 语言基础语法一 (快速入门 Go 语言)

Go语言基础语法一. golang 标识符&#xff0c;关键字&#xff0c;命名规则二. golang 变量三. golang 常量四. golang 数据类型五. golang 布尔类型六. golang 数字类型七. golang 字符串1. go语言字符串字面量2. go语言字符串连接(1). 使用加号(2). 使用 fmt.Sprintf() 函数(3…...

Java高效率复习-SpringMVC[SpringMVC-2]

SpringMVC获取请求参数 SpringMVC获取请求参数的两种方式↓ 通过ServletAPI获取请求参数 将HttpServletRequest作为控制器方法的形参&#xff0c;此时HttpServletRequest类型的参数表示封装了当前请求的请求报文的对象 通过request的API——getParameter(String s)方法来获取…...

【前端】一个更底层库-React基础知识点

目录Reat是什么&#xff1f;为什么要使用React类库比较容易学习&#xff0c;API非常少。组件内聚&#xff0c;容易组合原生组件和自定义组件融合渲染状态/属性驱动全局更新commonjs生态圈/工具栏完善React基础知识JSX概述JSX嵌入变量Event事件组合组合CHILDREN总结大家好&#…...

C++ 之枚举类型

文章目录参考描述枚举类型枚举类型枚举变量的声明及定义细节枚举常量的默认初始值枚举常量不可被修改赋值运算枚举常量与数据类型为枚举常量指定数据类型可选择的数据类型特殊的 Bool强枚举类型命名冲突强枚举类型参考 项目描述菜鸟教程C 枚举类型详解精通C &#xff08;第九版…...

软件测试用例(3)

按照测试对象划分: 一)界面测试: 1)软件只是一种工具&#xff0c;软件和人的信息交流是通过界面来进行的&#xff0c;界面是软件和用户交流的最直接的一层&#xff0c;界面的设计决定了用户对于我们设计软件的第一映像&#xff0c;界面如同人的面孔&#xff0c;具有最吸引用户的…...

Spring——Bean管理-注解方式进行属性注入

Spring针对Bean管理中创建对象提供的注解有哪些&#xff1f;Component&#xff1a;普通Service&#xff1a;业务逻辑层Controller&#xff1a;controller层Repository&#xff1a;dao层用注解的方式是为什么&#xff1f;简化xml方式开发&#xff0c;只需要注解就可以完成在配置…...

【设计模式之美 设计原则与思想:设计原则】20 | 理论六:我为何说KISS、YAGNI原则看似简单,却经常被用错?

上几节课中&#xff0c;我们学习了经典的 SOLID 原则。今天&#xff0c;我们讲两个设计原则&#xff1a;KISS 原则和 YAGNI 原则。其中&#xff0c;KISS 原则比较经典&#xff0c;耳熟能详&#xff0c;但 YAGNI 你可能没怎么听过&#xff0c;不过它理解起来也不难。 理解这两个…...

Java代码弱点与修复之——Copy-paste error(复制粘贴错误)

弱点描述 Copy-paste error,复制粘贴错误。 是指在复制和粘贴代码时产生的错误。这种错误通常是由于程序员在复制代码时未正确编辑所复制的代码或编辑复制后的代码时忘记更改一些值或参数而导致的。复制粘贴错误可能会导致程序逻辑错误、编译错误或运行时错误。 示例代码 …...

Editor.md 的使用方法及图片处理

目录1. 资源下载2. 生成页面2.1 编辑和预览页面2.2 文本渲染页面3. 图片上传3.1 前端配置3.2 后端接口4. 图片粘贴[^2]1. 资源下载 官网下载 gitee 下载 2. 生成页面 2.1 编辑和预览页面 将资源&#xff08;精简后 Editor.md 资源1&#xff09;导入项目&#xff1a; 按照官…...

剑指 Offer II 018. 有效的回文

题目链接 剑指 Offer II 018. 有效的回文 easy 题目描述 给定一个字符串 s&#xff0c;验证 s是否是 回文串 &#xff0c;只考虑字母和数字字符&#xff0c;可以忽略字母的大小写。 本题中&#xff0c;将空字符串定义为有效的 回文串 。 示例 1: 输入: s “A man, a plan, …...

Elasticsearch分析器(Analyzer)

Elasticsearch分析器&#xff08;Analyzer&#xff09; 文章目录Elasticsearch分析器&#xff08;Analyzer&#xff09;分析器概念内置分析器&#xff08;8.6版本&#xff09;自定义分析器elasticsearch-analysis-ik&#xff08;简称ik&#xff0c;&#x1f495;14.8k&#xff…...

P6入门:了解P6 Professional 工具栏及地图分享

目录 引言 相关分享 引言 凭借更大的灵活性和增强的自定义功能&#xff0c;最新版本的 Oracle Primavera P6 Professional 的界面比早期版本有了巨大改进。对于有经验的伙伴来说&#xff0c;它仍然是熟悉的领域&#xff0c;几乎所有预期的功能都显示在前面。该界面可以更好地…...

习题30 if elif else 语句

people 30#变量people赋值30 cars 40#变量cars赋值40 buses 15#变量buses赋值 if cars > people:#如果出租车比人多print("We should take the cars")#我们坐出租车 elif cars < people:#elif后面必须跟条件&#xff0c;print("We should not take the…...

32 openEuler使用LVM管理硬盘-管理卷组

文章目录32 openEuler使用LVM管理硬盘-管理卷组32.1 创建卷组32.2 查看卷组32.3 修改卷组属性32.4 扩展卷组32.5 收缩卷组32.6 删除卷组32 openEuler使用LVM管理硬盘-管理卷组 32.1 创建卷组 可在root权限下通过vgcreate命令创建卷组。 vgcreate [option] vgname pvname ...…...

Jackson CVE-2017-17485 反序列化漏洞

0x00 前言 同CVE-2017-15095一样&#xff0c;是CVE-2017-7525黑名单绕过的漏洞&#xff0c;主要还是看一下绕过的调用链利用方式。 可以先看&#xff1a; Jackson 反序列化漏洞原理 或者直接看总结也可以&#xff1a; Jackson总结 涉及版本&#xff1a;2.8.10和2.9.x至2.…...

十大排序(C++版)

测试排序的题目&#xff1a; 912. 排序数组 - 力扣&#xff08;LeetCode&#xff09; 堕落的做法&#xff1a; class Solution { public:vector<int> sortArray(vector<int>& nums) {sort(nums.begin(),nums.end());return nums;} };视频推荐&#xff1a; …...

SpringMVC中的常用注解

Java知识点总结&#xff1a;想看的可以从这里进入 目录3.2、常用的注解3.2、常用的注解 Controller&#xff1a;代表此类是一个控制器&#xff0c;需要配置包的扫描。Spring MVC 是通过组件扫描机制查找应用中的控制器类的 在Spring6.0之后要求控制层必须添加该注解才会被识别成…...

English Learning - L2-3 英音地道语音语调 小元音 [ʌ] [ɒ] [ʊ] [ɪ] [ə] [e] 2023.02.27 周一

English Learning - L2-3 英音地道语音语调 小元音 [ʌ] [ɒ] [ʊ] [ɪ] [ə] [e] 2023.02.27 周一课前活动练习方法大小元音总结小元音准备工作[ʌ] 中元音发音技巧对应单词的发音对应句子的发音常见的字母组合[ɒ] 后元音发音技巧对应单词的发音对应句子的发音常见的字母组合…...

fastadmin后台登录页修改

直接替换就行 <!DOCTYPE html> <html lang"{$config.language}"> <head>{include file"common/meta" /}<style type"text/css">body {color: #999;background-color: #f1f4fd;background-size: cover;}a {color: #444;…...

Java 面向对象(OOP)的三大特性

封装 所谓封装&#xff0c;意思就是隐藏内部细节&#xff0c;在编程中&#xff0c;指利用抽象数据类型将数据和基于数据的操作封装在一起&#xff0c;使其构成一个不可分割的独立实体&#xff0c;并尽可能地隐藏内部的细节&#xff0c;只保留一些对外接口使之与外部发生联系。…...

Java:openjdk: error: Student is abstract; cannot be instantiated;java编译环境

文章目录编译环境jdkopenjdk错误代码小心javac -verbos编译环境 jdk 需要安装的javac 在java-devel 包里 [root10 ~]# rpm -qf /usr/bin/javac file /usr/bin/javac is not owned by any package [root10 ~]# ll /usr/bin/javac lrwxrwxrwx. 1 root root 23 Jun 15 09:52 /us…...

28个案例问题分析---019---临时解决方案和最终解决方案--思想

临时解决方案与最终解决方案一&#xff1a;背景介绍二&#xff1a;临时解决方案&#xff1f;最终解决方案&#xff1f;概念如何选择三&#xff1a;总结一&#xff1a;背景介绍 项目中&#xff0c;出现了一个线上问题。 用户登陆之后看不到课程。重新登陆就可以看到课程。出现这…...

计算机网络的166个概念你知道几个 第四部分

HTML&#xff1a;HTML 称为超文本标记语言&#xff0c;是一种标识性的语言。它包括一系列标签&#xff0e;通过这些标签可以将网络上的文档格式统一&#xff0c;使分散的 Internet 资源连接为一个逻辑整体。HTML 文本是由 HTML 命令组成的描述性文本&#xff0c;HTML 命令可以说…...

Lenovo 联想-IdeaPad-Y530电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。硬件型号驱动情况主板联想-IdeaPad-Y530处理器Intel 酷睿2双核 T9400已驱动内存2GB已驱动硬盘2TB HP EX950 PCI-E Gen3 x4 NVMe SSD已驱动显卡NVIDIA GeForce 9300M GS无法驱动声卡Realtek ALC888无法驱动网卡RTL8168H Giga…...