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

MyBatis源码分析(六)MetaObject工具类的使用与源码分析
文章目录一、MetaObject基本使用二、关键类源码分析1、MetaObject的构造方法2、PropertyTokenizer分词器3、BeanWrapper4、MetaClass5、DefaultReflectorFactory6、Reflector7、总结三、MetaObject的getValue源码分析写在后面一、MetaObject基本使用 public class User {priva…...

文献资源最多的文献下载神器,99.99%的文献都可下载
用对工具事半功倍,查找下载文献用对工具能节约大量的时间和精力去做更多的事情。 文献党下载器(wxdown.org),几乎整合了所有文献数据库资源,涵盖各种文献类型,包含全部学科。文献党下载器整合的资源如&…...

工控机ARM工业边缘计算机搭建Node-Red环境
搭建Node-Red环境Node-RED是一个基于Node.js的开源可视化流程编程环境,可以轻松构建自定义应用程序,通过连接简单的节点来完成复杂的任务。Node-RED提供了一种简单的方法,可以快速连接到外部服务,从而实现物联网应用的开发。Node-…...

位图/布隆过滤器/海量数据处理方式
位图 位图的概念 所谓位图,就是用每一位来存放某种状态,适用于海量数据,数据无重复的场景。通常是用来判断某个数据存不存在的。 直接来看问题: 给40亿个不重复的无符号整数,没排过序。给一个无符号整数࿰…...

Tomcat 配置文件数据库密码加密
几年前研究过Tomcat context.xml 中数据库密码改为密文的内容,因为当时在客户云桌面代码没有留备份也没有文章记录,最近项目又提出了这个需求就又重新拾起来学习一下。在网上找了一些资料,自己也大概试了一下,目前功能是实现了。参…...

k8s-Kubernetes集群部署
文章目录前言一、Kubernetes简介与架构1.Kubernetes简介2.kubernetes设计架构二、Kubernetes集群部署1.集群环境初始化2.所有节点安装kubeadm3.拉取集群所需镜像3.集群初始化4.安装flannel网络插件5.扩容节点6.设置kubectl命令补齐前言 一、Kubernetes简介与架构 1.Kubernetes…...

Python数据分析案例19——上市银行财务指标对比
我代码栏目都是针对基础的python数据分析人群,比如想写个本科毕业论文,课程论文,做个简单的案例分析等。过去写的案例可能使用了过多的机器学习和深度学习方法,文科的同学看不懂,可能他们仅仅只想用python做个回归或者…...

Python 中错误 ConnectionError: Max retries exceeded with url
出现错误“ConnectionError: Max retries exceeded with url”有多种原因: 向 request.get() 方法传递了不正确或不完整的 URL。我们正受到 API 的速率限制。requests 无法验证您向其发出请求的网站的 SSL 证书。 确保我们指定了正确且完整的 URL 和路径。 # ⛔️…...

SpringBoot下的Spring框架学习(Tedu)——DAY02
SpringBoot下的Spring框架学习(Tedu)——DAY02 目录SpringBoot下的Spring框架学习(Tedu)——DAY02Spring框架学习1.1 Spring介绍1.2 知识铺垫1.2.1 编辑Dog类1.2.2 编辑Cat类1.2.3 编辑测试类User.java1.2.4 上述代码的总结1.3 面…...

容易混淆的点:C语言中char* a[] 与 char a[] 的区别以及各自的用法
char* a[] 和 char a[] 的区别 char* a[] 和 char a[] 是 C 语言中数组的不同声明方式,二者具有以下区别: char a[] 声明的是一个字符数组,其中存储的是一串字符。此时,a 可以被视为一个指向字符的指针。 char* a[]则声明了一个…...

认识Spring(下)
作者:~小明学编程 文章专栏:Spring框架 格言:热爱编程的,终将被编程所厚爱。 目录 Spring更加高效的读取和存储对象 存储bean对象 五大注解 关于五大类注解 对象的注入 属性注入 构造方法注入 Setter注入 三种注入方式的…...

Educational Codeforces Round 144 (Rated for Div. 2) C - Maximum Set
传送门 题意: 对于一个集合,如果它的任意两个元素都能 有 其中一个能整除另一个,那么它是好的。问在区间[L,R] 中由这个区间某些数内构成的好的集合的最长长度是多少,以及且满足这个长度的好集合有多少个。(懒得想就借…...

学python的第四天---基础(2)
一、三角形类型读入数组并排序的方法nlist(map(float,input().split())) c,b,asorted(n)list_1 list(map(float, input().split())) list_1.sort() list_1.reverse()lengthssorted(map(float,input().split(" ")),reverseTrue)二、动物写法一:d{" &…...

spring之refresh流程-Java八股面试(六)
系列文章目录 第一章 ArrayList-Java八股面试(一) 第二章 HashMap-Java八股面试(二) 第三章 单例模式-Java八股面试(三) 第四章 线程池和Volatile关键字-Java八股面试(四) 第五章ConcurrentHashMap-Java八股面试(五) 动态每日更新算法题,想要学习的可以关注一下…...

【C语言】刷题|链表|双指针|指针|多指针|数据结构
主页:114514的代码大冒 qq:2188956112(欢迎小伙伴呀hi✿(。◕ᴗ◕。)✿ ) Gitee:庄嘉豪 (zhuang-jiahaoxxx) - Gitee.com 文章目录 目录 文章目录 前言 一、移除链表元素 二、反转链表 三,链表的中间结点 四&…...

糖化学类854262-01-4,Propargyl α-D-Mannopyranoside,炔丙基 α-D-吡喃甘露糖苷
外观以及性质:Propargyl α-D-Mannopyranoside一般为白色粉末状,糖化学类产品比较多,一般包括:葡萄糖衍生物、葡萄糖醛酸衍生物,氨基甘露糖衍生物、半乳糖衍生物、氨基半乳糖衍生物、核糖衍生物、阿拉伯糖衍生物、唾液…...

项目管理工具DHTMLX 在 G2 排名中再创新高
DHTMLX Gantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表。可满足项目管理应用程序的大部分开发需求,具备完善的甘特图图表库,功能强大,价格便宜,提供丰富而灵活的JavaScript API接口,与各种服务器端技术&am…...

28 位委员出席,龙蜥社区第 15 次运营委员会会议顺利召开
2 月 24 日,龙蜥社区在海光召开了第 15 次运营委员会会议,本次会议由统信软件运营委员会委员崔开主持。来自 Arm、阿里云、飞腾、红旗软件、海光、Intel、龙芯、联通软研院、浪潮信息、普华基础软件、统信软件、万里红、移动、中科方德等理事单位的 28 位…...

自然语言处理-基于预训练模型的方法-chapter3基础工具集与常用数据集
文章目录3.1NLTK工具集3.1.1常用语料库和词典资源3.1.2常见自然语言处理工具集3.2LTP工具集3.3pytorch基础3.3.1张量基本概念3.3.2张量基本运算3.3.3自动微分3.3.4调整张量形状3.3.5广播机制3.3.6索引与切片3.3.7降维与升维3.4大规模预训练模型3.1NLTK工具集 3.1.1常用语料库和…...

【SpringMVC】@RequestMapping
RequestMapping注解 1、RequestMapping注解的功能 从注解名称上我们可以看到,RequestMapping注解的作用就是将请求和处理请求的控制器方法关联起来,建立映射关系。 SpringMVC 接收到指定的请求,就会来找到在映射关系中对应的控制器方法来处…...

【深度学习】BERT变体—SpanBERT
SpanBERT出自Facebook,就是在BERT的基础上,针对预测spans of text的任务,在预训练阶段做了特定的优化,它可以用于span-based pretraining。这里的Span翻译为“片段”,表示一片连续的单词。SpanBERT最常用于需要预测文本…...

根据身高体重计算某个人的BMI值--课后程序(Python程序开发案例教程-黑马程序员编著-第3章-课后作业)
实例3:根据身高体重计算某个人的BMI值 BMI又称为身体质量指数,它是国际上常用的衡量人体胖瘦程度以及是否健康的一个标准。我国制定的BMI的分类标准如表1所示。 表1 BMI的分类 BMI 分类 <18.5 过轻 18.5 < BMI < 23.9 正常 24 < BM…...

高并发编程JUC之进程与线程高并发编程JUC之进程与线程
1.准备 pom.xml 依赖如下: <properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target&g…...

css基础
1-css引入方式内嵌式style(学习)<style>p {height: 200;}</style>外联式link(实际开发)<link rel"stylesheet" href"./2-my.css">2-选择器2.1标签选择器(标签名相同的都生效&am…...

Unity - 搬砖日志 - BRP 管线下的自定义阴影尺寸(脱离ProjectSettings/Quality/ShadowResolution设置)
文章目录环境原因解决CSharp 脚本效果预览 - Light.shadowCustomResolution效果预览 - Using Quality Settings应用ControlLightShadowResolution.cs ComponentTools Batching add the Component to all LightReferences环境 Unity : 2020.3.37f1 Pipeline : BRP 原因 (好久没…...

如何在SSMS中生成和保存估计或实际执行计划
在引擎数据库执行查询时执行的过程的步骤由称为查询计划的一组指令描述。查询计划在SQL Server中也称为SQL Server执行计划,我们可以通过以下步骤来生成和保存估计或实际执行计划。 估计执行计划和实际执行计划是两种执行计划: 实际执行计划:当执行查询时,实际执行计划出…...

mac 环境下安装MongoDB
目录 一、下载MongoDB数据库并进行安装 二. 解压放在/usr/local目录下 三. 配置环境变量 “无法验证开发者”的解决方法 mongodb可视化工具的安装与使用 一、下载MongoDB数据库并进行安装 下载地址:https://www.mongodb.com/try/download/community 二. 解压…...

RTOS中相对延时和绝对延时的区别
相信许多朋友都有过这么一个需求:固定一个时间(周期)去处理某一件事情。 比如:固定间隔10ms去采集传感器的数据,然后通过一种算法计算出一个结果,最后通过指令发送出去。 你会通过什么方式解决呢…...

Solon2 项目整合 Nacos 配置中心
网上关于 Nacos 的使用介绍已经很多了,尤其是与 SpringBoot 的整合使用。怎么安装也跳过了,主要就讲 Nacos 在 Solon 里的使用,这个网上几乎是没有的。 1、认识 Solon Solon 一个高效的应用开发框架:更快、更小、更简单…...

Linux 路由表说明
写在前面: 本文章旨在总结备份、方便以后查询,由于是个人总结,如有不对,欢迎指正;另外,内容大部分来自网络、书籍、和各类手册,如若侵权请告知,马上删帖致歉。 目录route 命令字段分…...