On 11/12/19 4:15 AM, SealabJaster wrote:
On Monday, 11 November 2019 at 16:56:31 UTC, Steven Schveighoffer wrote:
The tough part about serializing classes is if the class is not final, how do you serialize the derived data. It requires some sort of user help to
tell it how to get at the data.

And if you do allow things such as letting classes have a 'deserialise' member function which can be overloaded, you still need to create or be given an instance of the class beforehand, which brings things back around to the "constructor issue" in the latest post.

I don't quite know if there's actually an automatic solution for classes that covers most cases? Anything I can think of places limitations in some form or another.

There's definitely not an automatic solution. However, in my jsoniopipe code, the base class can have a static function fromJSON that initializes the requested type. Such a thing has to be a member, but in theory could just be a registered callback.

In my use case, I have a base class and all the derivatives in the same module (they are just messages). Here is some code that returns the base type that is portable to any such situation:

    static Base fromJSON(JT)(ref JT tokenizer, ReleasePolicy relPol)
    {
        // this creates a rewind point, so I can go back and parse the
        // object after finding the type.
        tokenizer.startCache();
        if(tokenizer.parseTo("type")) // this part depends on the encoding
        {
            string t;
            // get the type name
            tokenizer.deserialize(t);
            import std.meta;
            // alias to the module for Base, which also contains all the
            // derivatives
            alias mod = __traits(parent, Base);
            enum isBase(string s) =
                is(__traits(getMember, mod, s) : Base) &&
                !is(__traits(getMember, mod, s) == Base);

            // this gets all the classes in this module that are
            // derivatives of Base (except Base). D is so cool ;)
            alias Derivatives = Filter!(isBase, __traits(allMembers, mod));
// reset the tokenizer to read the whole JSON data for this object
            tokenizer.rewind();
            tokenizer.endCache();
            switch(t)
            {
                static foreach(typename; Derivatives)
                {
                // Note: MyType is the JSON string that designates the
                // type, your implementation may vary.
                case __traits(getMember, mod, typename).MyType:
                    {
auto result = new __traits(getMember, mod, typename);
                        // defined by the library, does a rote
                        // serialization of members.
                        tokenizer.deserializeAllMembers(result, relPol);
                        return result;
                    }
                }
            default:
                assert(false, "Unknown type identifier: " ~ t);
            }
        }
        assert(false, "Couldn't find type identifier");
    }

Basically, I never have to touch this again, thanks D. Just add a new type that derives from Base with a proper MyType member, and it gets added to the list. It just has to be added to the module itself. If your class hierarchy is spread out in different files, you can make some kind of registration scheme to handle the deserialization.

-Steve
            • Re: ... JN via Digitalmars-d-announce
              • ... Patrick Schluter via Digitalmars-d-announce
              • ... Martin Tschierschke via Digitalmars-d-announce
              • ... Laurent TrĂ©guier via Digitalmars-d-announce
            • Re: ... SealabJaster via Digitalmars-d-announce
              • ... JN via Digitalmars-d-announce
              • ... Steven Schveighoffer via Digitalmars-d-announce
    • Re: Blog series to te... SealabJaster via Digitalmars-d-announce
  • Re: Blog series to teach a... Steven Schveighoffer via Digitalmars-d-announce
    • Re: Blog series to te... SealabJaster via Digitalmars-d-announce
      • Re: Blog series t... Steven Schveighoffer via Digitalmars-d-announce
      • Re: Blog series t... SealabJaster via Digitalmars-d-announce
        • Re: Blog seri... SealabJaster via Digitalmars-d-announce
          • Re: Blog ... SealabJaster via Digitalmars-d-announce
            • Re: ... SealabJaster via Digitalmars-d-announce
              • ... Greatsam4sure via Digitalmars-d-announce
              • ... jmh530 via Digitalmars-d-announce
              • ... drug via Digitalmars-d-announce
              • ... Steven Schveighoffer via Digitalmars-d-announce
      • Re: Blog series t... Jacob Carlborg via Digitalmars-d-announce

Reply via email to