Search Unity

Polymorphic serialization with JsonFX

Discussion in 'Scripting' started by liortal, Sep 22, 2014.

  1. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    We are using JsonFX to serialize/deserialize objects to JSON in our game.

    I've currently hit some limitation related to polymorphism that i don't know how to handle.

    Consider the following code:

    Code (CSharp):
    1. [JsonOptIn]
    2. public class SomeObject : GameObjectWrapper
    3. {
    4.     [JsonMember]
    5.     public List<GameObjectWrapper> Children;
    6. }
    This is a container type of object that can contain other elements (of type GameObjectWrapper).

    The class GameObjectWrapper is a base class, and many different types of objects derive from it (this container can have many different types of objects under it).

    The problem is, that with JsonFX, when deserializing this back into an object from JSON, i get a reference to the base class (GameObjectWrapper), and not the the concrete class.

    My questions are:

    1. Is there any way to overcome this issue easily ?
    2. Is there any other recommended JSON library for Unity that you're using ? (it seems that JsonFX is not regularly updated anymore).
     
  2. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    You could do it with JSON .NET (using my Unity port in the asset store). Does GameObjectWrapper inherit from GameObject or is it just to contain some of the logic?

    Asset Store Link


    With JSON .NET you would serialize your SomeObject instance (or just the Children property if you want). You use the serialization overload that accepts JsonSerializerSettings and set the TypeNameHandling to .All which will store the type names with the JSON and make sure the inherited classes are serialized and constructed and deserialized properly:

    Code (csharp):
    1.  
    2. var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
    3. var jsonString = JsonConvert.SerializeObject(yourObject, Formatting.None, settings);
    4.  
    You'll need to do the same when deserializing but it will work. This assumes though that it doesn't actually inherit from GameObject itself as there are some internal properties that JSON .NET can't handle (like rigidBody) because of Unity's overload of the == operator. JSON .NET attempts to serialize because it can see that they aren't actually null, but Unity will throw an internal exception. You could still make it work with GameObject but you'd need to write your own type converter for it.
     
  3. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    Do JSON.NET and JsonFx have any common history ? The API seems pretty similar.
     
  4. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    I couldn't tell you to be honest. They are very similar though, but I don't know a whole lot about JsonFx.

    I know some former JsonFx users who are using my asset have said the conversion was pretty easy.
     
  5. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    OK, i will have a look.

    GameObjectWrapper is a bad name - it is not related to Unity's GameObject.
     
  6. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Oh, should be a piece of cake then. ;) If you do pick it up, check out the Examples / Tests. There's a test scene. You may have to hook the TextTest script back up to the ScriptHost object in the test scene. For some reason, Unity 3.5 annoyingly keeps breaking that link when I export the unity package but I have to use 3.5 for asset store submission. Anyway, there is a Polymorphic test in there that shows the usage and I'd be happy to help with any questions you have.
     
  7. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    Thanks for the assistance.

    I will take it with my TL: although a single payment of 20$ is not much, it's the process of changing the current library we use, and i'm unsure we could be performing that ATM.

    Also, why is there a Unity specific version of Json.NET ? i believe it's also available as an open source package (not Unity specific) for different .NET platforms.
     
  8. billykater

    billykater

    Joined:
    Mar 12, 2011
    Posts:
    329
    We are using JsonFx just fine for polymorphic list entries. You have to enable TypeHints for this to work though.

    Code (csharp):
    1.  
    2. WriterSettings = new JsonWriterSettings
    3.    {
    4.       TypeHintName = "TypeName",
    5.    }
    6. var jsonDataWriter = new JsonDataWriter(WriterSettings);
    7.  
    8. ReaderSettings = new JsonReaderSettings
    9.    {
    10.       TypeHintName = "TypeName",
    11.    }
    12. var jsonDataReader = new JsonDataReader(ReaderSettings);
    13.  
     
  9. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    I have enabled this. It serializes just fine (writes the type hints).
    When deserializing though, it still creates the base class instead of the derived class.

    Could you please show the code you use for actually writing/reading the object from and into JSON ?
     
  10. billykater

    billykater

    Joined:
    Mar 12, 2011
    Posts:
    329
    Seems like we have a lot more company specific code changes to JsonFx than I expected. So someone might have fixed that issue in our JsonFx fork (nothing obvious from just browsing through the changes).

    That is how the deserialization method looks like for us.
    Code (csharp):
    1.  
    2. T Deserialize<T>(TextReader textReader) where T : class
    3. {
    4.     var jsonDataReader = new JsonDataReader(ReaderSettings);
    5.     return jsonDataReader.Deserialize(textReader, typeof (T)) as T;
    6. }
    7.  
    Sorry if I got your hopes up too much and this was fixed in our fork. Searching for "jsonfx polymorphism" on the web gives some indications that you might need to change a few code pieces for it to work (although checking with our code base they are without these changes).
     
  11. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Because the official package doesn't work in all platforms in Unity. It works for standalone and that's pretty much it. That's where my version came from. It's an AOT and Unity compatible port.
     
  12. FlorentFal

    FlorentFal

    Joined:
    Nov 20, 2015
    Posts:
    55