Obotcha的反射基本已经都实现。目前能支持数据库,xml,json的ORM实现。
template<typename T>
void reflectTo(T obj)
template<typename T>
void importFrom(T value)
JsonValue目前提供如上两个接口,reflectTo是将json数据直接导入到class对象中。importFrom是将class对象数据直接转成json数据。接下来我们看以下reflectTo和importFrom的实现吧:
template<typename T>
void reflectTo(T obj) {
sp<_JsonValueIterator> iterator = this->getIterator();
while(iterator->hasValue()) {
String key = iterator->getTag();
Field field = obj->getField(key);
if(field == nullptr) {
printf("key is %s \n",key->toChars());
iterator->next();
continue;
}
std::string name = field->getName()->getStdString();
JsonValue jsonnode = iterator->getValue();
switch(field->getType()) {
case FieldTypeLong:{
String value = jsonnode->getString();
field->setValue(value->toBasicLong());
}
break;
case FieldTypeInt: {
String value = jsonnode->getString();
field->setValue(value->toBasicInt());
}
break;
case FieldTypeByte:{
String value = jsonnode->getString();
field->setValue(value->toBasicByte());
}
break;
case FieldTypeBool:{
String value = jsonnode->getString();
field->setValue(value->toBasicBool());
}
break;
case FieldTypeDouble:{
String value = jsonnode->getString();
field->setValue(value->toBasicDouble());
}
break;
case FieldTypeFloat:{
String value = jsonnode->getString();
field->setValue(value->toBasicFloat());
}
break;
case FieldTypeString:{
String value = jsonnode->getString();
field->setValue(value);
}
break;
case FieldTypeUint8:{
String value = jsonnode->getString();
field->setValue(value->toBasicUint8());
}
break;
case FieldTypeUint16:{
String value = jsonnode->getString();
field->setValue(value->toBasicUint16());
}
break;
case FieldTypeUint32:{
String value = jsonnode->getString();
field->setValue(value->toBasicUint32());
}
break;
case FieldTypeUint64:{
String value = jsonnode->getString();
field->setValue(value->toBasicUint64());
}
break;
case FieldTypeObject: {
//create Objectt
printf("createobj name is %s\n",name.c_str());
field->createObject();
auto reflectValue = field->getObjectValue();
if(reflectValue != nullptr) {
printf("create obj not null \n");
} else {
printf("create obj null \n");
}
jsonnode->reflectTo(reflectValue);
}
break;
case FieldTypeArrayList:
jsonnode->reflectToArrayList(obj,field->getName());
break;
}
iterator->next();
}
}
主要就是通过json节点的name去查找Class对应的成员变量的field。接下来再通过这个field去设定数据。和Java的反射有点类似。这里主要留意两点:
1.如果成员变量不是简单的数据类型,而且一个struct或者class,那反射得到的都是Object类(主要是getObjectValue虽然用了auto返回值,但是C++14/11/17编译的时候都规定,同一个函数的auto返回类型必须一致,所以只能返回Object类)。
2.成员变量是ArrayList的反射比较复杂,因为通过getObjectValue得到的数据都是Object,已经无法获取ArrayList<T>中的T类型,后续想创建T的实例基本就不可能了。所以目前的方法是Field中有一个createListItemObject 函数,这个函数直接来创建T的实例,而且创建的同时,这个实例会自动加到Field对应的ArrayList中去。所以如果要反射ArrayList,需要编写类似下面的代码:
template<typename T>
void reflectToArrayList(T obj,String name) {
Field field = obj->getField(name);
field->createObject(); //创建ArrayList实例
int size = this->size();
for(int index = 0;index<size;index++) {
//创建ArrayList中的Item实例,同时该实例会自动添加到ArrayList
auto vv = field->createListItemObject();
JsonValue value = this->getValueAt(index);
value->reflectTo(vv);
}
}
反射相关的代码如下:
https://github.com/wangsun1983/Obotcha/blob/master/lang/include/Reflect.hpp
基本思路都是通过宏/模板+tuple来实现。