MetaObject源码解析

MetaObject是个反射工具类它支持以“点.”的方式向下递归反射创建对象,属性赋值以及通过key名获取集合对象。

测试

public void shouldGetAndSetNestedField() {
// 创建一个普通bean
RichType rich = new RichType();
// 将bean包装成MetaObject对象
MetaObject meta = SystemMetaObject.forObject(rich);
// 以map的方式
meta.setValue("richType.richMap[key]", "foo");
// 以属性的方式
meta.setValue("richType.richField", "foo");
// 不用.的方式,只能支持到二级属性
meta.setValue("richProperty", "foo");
System.out.println(meta.getValue("richType.richMap[key]"));
System.out.println(meta.getValue("richType.richField"));
System.out.println(meta.getValue("richProperty"));
}
// bean的结构
public class RichType {
private String richField;
private String richProperty;
private Map richMap = new HashMap();
}

 

forObject,简单来说就是包装一个对象赋予一些能力

private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory) {
this.originalObject = object;// 源对象
this.objectFactory = objectFactory;// 对象工厂
this.objectWrapperFactory = objectWrapperFactory;// 对象包装器工厂
// 对象包装器
if (object instanceof ObjectWrapper) {
//如果对象本身已经是ObjectWrapper型,则直接赋给objectWrapper
this.objectWrapper = (ObjectWrapper) object;
} else if (objectWrapperFactory.hasWrapperFor(object)) {
//如果有包装器,调用ObjectWrapperFactory.getWrapperFor
this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
} else if (object instanceof Map) {
//如果是Map型,返回MapWrapper
this.objectWrapper = new MapWrapper(this, (Map) object);
} else if (object instanceof Collection) {
//如果是Collection型,返回CollectionWrapper
this.objectWrapper = new CollectionWrapper(this, (Collection) object);
} else {
//除此以外,返回BeanWrapper
this.objectWrapper = new BeanWrapper(this, object);
}
}

分词器源码,主要是将我们的传入的值进行分割

public class PropertyTokenizer implements Iterable<PropertyTokenizer>, Iterator<PropertyTokenizer> {
// 例子:richType.richMap[key]
// 当前字段名
private String name; //richType
private String indexedName; //richType
// 下标,如果有值说明子属性有集合类型的
private String index; //0
// .后面的字段
private String children; //richMap
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);
}
}

 setValue,递归调用,思路是先创建上层对象再创建下层属性(对象),知道最上层的对象才能知道它拥有什么属性

public void setValue(String name, Object value) {
// 分词器进行分词,如richType.richMap[key],返回richType,子属性为richMap[key]
PropertyTokenizer prop = new PropertyTokenizer(name);
// 是否有子属性
if (prop.hasNext()) {
// 内部就是递归调用,并将调用获取的值进行包装成MetaObject对象
// 此时传入的richType后面没有.就是直接创建这个对象了。
MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
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.instantiatePropertyValue创建新实例
metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory);
}
}
//递归调用setValue,给子属性赋值
metaValue.setValue(prop.getChildren()/*子属性名称*/, value);
} else {
//到了最后一层了,所以委派给ObjectWrapper.set,调用setter方法
objectWrapper.set(prop, value);
}
}

metaObjectForProperty 没什么好说的,就是将当前对象包装成MetaObject,如果返回null说明是类不是属性就会进入上面的第5行代码里面的逻辑

public MetaObject metaObjectForProperty(String name) {
//实际是递归调用
Object value = getValue(name);
return MetaObject.forObject(value, objectFactory, objectWrapperFactory);
}

getValue套路跟setValue一样的,获取prop.name字段的对象

public Object getValue(String name) {
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext()) {
MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
//如果上层就是null了,那就结束,返回null
return null;
} else {
//否则继续看下一层,递归调用getValue
return metaValue.getValue(prop.getChildren());
}
} else {
return objectWrapper.get(prop);
}
}

objectWrapper.get(prop, value)(objectWrapper.set(prop, value)); 两个作用,解析集合并赋值返回,反射调用对象的getter方法

@Override
public Object get(PropertyTokenizer prop) {
//如果有index(有中括号),说明是集合,那就要解析集合
if (prop.getIndex() != null) {
// 内部还是递归调用getValue,主要是通过反射获取并创建集合属性对象,到最终都会走向getBeanProperty方法
Object collection = resolveCollection(prop, object);
// 给集合赋值并获取
return getCollectionValue(prop, collection);
} else {
//否则,getBeanProperty,底层通过反射调用getter方法
return getBeanProperty(prop, object);
}
}
// 如上
public void set(PropertyTokenizer prop, Object value) {
if (prop.getIndex() != null) {
Object collection = resolveCollection(prop, object);
setCollectionValue(prop, collection, value);
} else {
setBeanProperty(prop, object, value);
}
}

 集合赋值方法

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 ReflectionException("The '" + prop.getName() + "' property of " + collection + " is not a List or Array.");
}
}
}

整体流程图

总结:通过分词区分当前属性和子属性,通过反射先创建当前属性,后创建子属性,反复循环操作。

 

posted @   猫长寿  阅读(281)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
点击右上角即可分享
微信分享提示