对于反射工具箱,前面学习了Reflector还有类型解析TypeParameterResolver,都是不咋好理解的,今天接着来点思维简单点的。
ObjectFactory
这是用来创建实体对象的接口。代码如下:
public interface ObjectFactory {
//设置配置信息
void setProperties(Properties properties);
//通过无参构造器创建实体对象
<T> T create(Class<T> type);
//通过参数列表,从指定类型中选择合适的构造器创建对象
<T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);
//检测指定类型是否是集合类型,主要处理java.util.Collection及其子类
<T> boolean isCollection(Class<T> type);
}
然后DefaultObjectFactory是上面接口的唯一实现方法,里面的create()方法是通过调用instantiateClass()方法实现的。
T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
try {
Constructor<T> constructor;
//通过无参构造函数创建对象
if (constructorArgTypes == null || constructorArgs == null) {
constructor = type.getDeclaredConstructor();
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
return constructor.newInstance();
}
//通过指定的参数列表查找构造函数,然后实例化对象。
constructor = 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 && !constructorArgTypes.isEmpty()) {
for (Class<?> argType : constructorArgTypes) {
argTypes.append(argType.getSimpleName());
argTypes.append(",");
}
argTypes.deleteCharAt(argTypes.length() - 1); // remove trailing ,
}
StringBuilder argValues = new StringBuilder();
if (constructorArgs != null && !constructorArgs.isEmpty()) {
for (Object argValue : constructorArgs) {
argValues.append(String.valueOf(argValue));
argValues.append(",");
}
argValues.deleteCharAt(argValues.length() - 1); // remove trailing ,
}
throw new ReflectionException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + e, e);
}
}
到这里就完事了,以上这个ObjectFactory接口还可以通过自定义类去实现接口,去实现自己需要的实体类初始化等操作。比如这篇博客里面介绍的:https://blog.csdn.net/fageweiketang/article/details/80794847
Property工具集
三种属性工具类:PropertyTokenizer、PropertyNamer、PropertyCopier.
首先是PropertyTokenizer.
比如我们在xml中设置属性表达式的时候,设计了这样一条:
orders[0].items[0].name
那么对于这样的表达式,就可以使用PropertyTokenizer来解析,该类中具体字段如下:
//当前表达式名称
private String name;
//当前表达式的索引名
private String indexedName;
//索引下标
private String index;
//子表达式
private String children;
然后在PropertyTokenizer的构造方法中,就会对传入的表达式进行解析,初始化上面的字段:
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);
}
}
代码的思路如下图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cV96W1Uv-1591095191576)(/img/artImg/lyc021849561591094995685.jpg ‘‘图片title’’)]
特别清晰哈哈,一看就能明白,不赘述了。
然后是PropertyNamer,提供一些静态方法,完成方法名到属性名的转换(也就是把方法名中的is、get、set去掉)
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 ReflectionException("Error parsing property name '" + name + "'. Didn't start with 'is', 'get' or 'set'.");
}
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;
}
PropertyCopier,和名字意义一样,是用于属性拷贝,实现相同类型的两个对象之间的属性值拷贝,主要由copyBeanProperties实现:
public static void copyBeanProperties(Class<?> type, Object sourceBean, Object destinationBean) {
Class<?> parent = type;
while (parent != null) {
final Field[] fields = parent.getDeclaredFields();
for(Field field : fields) {
try {
field.setAccessible(true);
field.set(destinationBean, field.get(sourceBean));
} catch (Exception e) {
// Nothing useful to do, will only fail on final fields, which will be ignored.
}
}
parent = parent.getSuperclass();
}
}
个人博客 http://qlumen.cn/fore