Search code examples
jsondeserializationhaxe

Deserializing a JSON string to a class instance in Haxe


I am trying to deserialize a JSON string into a class instance in Haxe.

class Action
{
    public var id:Int;
    public var name:String;

    public function new(id:Int, name:String)
    {
        this.id = id;
        this.name = name;
    }
}

I would like to do something like this:

var action:Action = haxe.Json.parse(actionJson);
trace(action.name);

However, this produces an error:

TypeError: Error #1034: Type Coercion failed: cannot convert Object@3431809 to Action


Solution

  • Json doesn't have a mechanism to map language specific data types and only supports a subset of the data types included in JS. To keep the information about the Haxe types you can certainly build your own mechanism.

    // This works only for basic class instances but you can extend it to work with 
    // any type.
    // It doesn't work with nested class instances; you can detect the required
    // types with macros (will fail for interfaces or extended classes) or keep
    // track of the types in the serialized object.
    // Also you will have problems with objects that have circular references.
    
    class JsonType {
      public static function encode(o : Dynamic) {
        // to solve some of the issues above you should iterate on all the fields,
        // check for a non-compatible Json type and build a structure like the
        // following before serializing
        return haxe.Json.stringify({
          type : Type.getClassName(Type.getClass(o)),
          data : o
        });
      }
    
      public static function decode<T>(s : String) : T {
        var o = haxe.Json.parse(s),
            inst = Type.createEmptyInstance(Type.resolveClass(o.type));
        populate(inst, o.data);
        return inst;
      }
    
      static function populate(inst, data) {
        for(field in Reflect.fields(data)) {
          Reflect.setField(inst, field, Reflect.field(data, field));
        }
      }
    }