Mix.install/2 and Jason.encode! of non-owned structs

I have been trying to JSON-encode structs defined in ExTwitter, such as ExTwitter.Model.Relationship for instance (the goal is to serialise them in a format which can be parsed from any language, or by a human easily), in a Mix.install/2 script.

I first learned that structs must be handled a bit specifically in such scripts (see Mix.install and structs).

After following the advice given, I had the expected error message:

(Protocol.UndefinedError) protocol Jason.Encoder not implemented for #ExTwitter.Model.Relationship<connections: nil, id: nil, id_str: nil, name: nil, screen_name: "TOTO", ...> of type ExTwitter.Model.Relationship (a struct), Jason.Encoder protocol must always be explicitly implemented.

If you own the struct, you can derive the implementation specifying which fields should be encoded to JSON:

    @derive {Jason.Encoder, only: [....]}
    defstruct ...

It is also possible to encode all fields, although this should be used carefully to avoid accidentally leaking private information when new fields are added:

    @derive Jason.Encoder
    defstruct ...

Finally, if you don't own the struct you want to encode to JSON, you may use Protocol.derive/3 placed outside of any module:

    Protocol.derive(Jason.Encoder, NameOfTheStruct, only: [...])
    Protocol.derive(Jason.Encoder, NameOfTheStruct)
. This protocol is implemented for the following type(s): Any, Atom, BitString, Date, DateTime, Decimal, Float, Integer, Jason.Fragment, Jason.OrderedObject, List, Map, NaiveDateTime, Time

Since I do not own the struct I want to encode, I attempted to run Protocol.derive(Jason.Encoder, ExTwitter.Model.Relationship) from inside a compiled method, but this does not work either (and the error message remains).

What works, so far, is leveraging Map.from_struct.

Is this a caveat we want to see in the documentation, or is there maybe a way to make it work without Map.from_struct, which I didn’t see?

Thanks!

Sounds like you may be stuck - the protocol stuff is specifically compile-time / outside-of-modules machinery, but the struct isn’t available then… :thinking:

There is an option in Mix.install to prevent protocol consolidation. That should allow you to implement it.