mardi 20 avril 2021

Serialize objects to JSON using custom reflection

I'm writing a custom runtime reflection system to serialize the objects of my application (a game, so game entities).

My reflection framework is really simple, it allows me to reflect data types and attach data members, constructors and member functions to these meta types:

// reflect built-in types
    Reflect::Reflect<int>("int");
    Reflect::Reflect<float>("float");
    Reflect::Reflect<std::string>("string");

// reflect TransformComponent
    Reflect::Reflect<TransformComponent>("TransformComponent")
    .AddConstructor<>()
    .AddDataMember<&TransformComponent::SetPosition, &TransformComponent::GetPosition>("position")
    .AddDataMember<&TransformComponent::SetId, &TransformComponent::GetId>("id")               
    .AddDataMember(&TransformComponent::mName, "name")
    .AddDataMember(&TransformComponent::f, "f");

I can use reflected members to set and get data members (which can have attached setters and getters) or to construct instances of reflected types:

Reflect::any transformComponentAny = Reflect::Resolve("TransformComponent")->GetConstructor<>()->NewInstance();

// using reflection to set and get object fields
    Reflect::any positionAny = Reflect::Resolve("Vector3D")->GetConstructor<>()->NewInstance();
    Reflect::Resolve("Vector3D")->GetDataMember("x")->Set(positionAny, 22.22f);
    Reflect::Resolve("Vector3D")->GetDataMember("y")->Set(positionAny, 130.12f);
    Reflect::Resolve("Vector3D")->GetDataMember("z")->Set(positionAny, 545.12f);

    Reflect::Resolve("TransformComponent")->GetDataMember("f")->Set(transformComponentAny, 0.009f);
    Reflect::Resolve("TransformComponent")->GetDataMember("position")->Set(transformComponentAny, positionAny);
    Reflect::Resolve("TransformComponent")->GetDataMember("id")->Set(transformComponentAny,32325);
    Reflect::Resolve("TransformComponent")->GetDataMember("name")->Set(transformComponentAny, std::string("hey a transform, again..."));  

all objects are wrapped inside a class like std::any, which abstract the real object, and mantains a type descriptor of the object type (to perform casts, conversions etc..)

Now, this is all ordinary reflection stuff I guess, what I'm stuck on is how to serialize my objects (which is the whole point of all this stuff).

When I want to serialize a member of an object to a JSON, I can easily retrieve the value, given the type descriptor of the object, the meta data member and the instance of the object:

auto typeDesc = object.GetType();  // get the type descriptor for the object (this is a any object)
for (auto dataMember : typeDesc->GetDataMembers())  
{
     auto fieldName = dataMember->GetName();
     auto fieldType = dataMember->GetType()->GetName();

     any field = dataMember->Get(object);

    if (fieldType == "int")                       
        json[fieldName] = field.Get<int>();
    else if (fieldType == "string")
        ....
}

what I want is to avoid the explicit check for the runtime type and the cast to the type. I'd like something like this:

json[fieldName] = field  // field is a any, it has no info about type at compile time

and let the meta type perform the necessary cast. I'm able to do it when deserializing from a JSON, since the meta types preserve the compile time type of the data member they represent, while any just keeps a type descriptor of the object it contains (I need to call any.Get<> at compile time with the appropriate type).

Any ideas about how to do it?





Aucun commentaire:

Enregistrer un commentaire