Парсим json в свои классы на Haxe

haxe-logoЦель:  к примеру, у нас есть редактор уровней, который оперирует сложной иерархией классов. Мы хотим сохранить наши уровни со всей сложной иерархией в json и когда необходимо достать из json без лишних телодвижений.

Наши «сложные» классы данных:

class Level
{
	public var id:Int;
	public var rocks:Array<Rock>;
	
	public function new()
	{
		
	}
}
class Rock
{
	public var x:Float;
	public var y:Float;
	public var text:String;
	
	public function new()
	{
		
	}
}

 На самом деле никаких велосипедов для этого изобретать не нужно.

Для начала устанавливаем TJson  — это библиотека для комфортной работы с json на Haxe независимо от таргета.

haxelib install tjson

Не забываем подключить библиотеку в проект:

<haxelib name="tjson" />

Теперь нам понадобится класс EXTJsonSerialization.hx  — качаем по ссылке и добавляем в проект. (спасибо доброму человеку написавшему его)

Ну вот теперь берем наши «сложные» классы и проверяем, как это работает.

var level = new Level();
level.rocks = new Array<Rock>();
var rock = new Rock();
rock.x = 1;
rock.y = 10;
rock.text = "Go to left";
level.rocks.push(rock);
rock = new Rock();
rock.x = 90;
rock.y = 400;
rock.text = "Go to right";
level.rocks.push(rock);
// Собственно encode класса Level в json:
trace(EXTJsonSerialization.encode(level, Level));

Получаем вот такой json:

{
     "id" : 0
    ,"_explicitType" : "examples.Level"
    ,"rocks" : [
         {
             "_explicitType" : "examples.Rock"
            ,"y" : 10
            ,"x" : 1
            ,"text" : "Go to left"
        }
        ,{
             "_explicitType" : "examples.Rock"
            ,"y" : 400
            ,"x" : 90
            ,"text" : "Go to right"
        }
    ]
}

Обратите внимание на поле «_explicitType» — оно расставляется в каждом объекте и указывает на его тип, чтобы у нас не возникло проблем при парсинге. Таким образом, иерархия наших классов с данными может быть практически любой.

Обратная магия работает одной строкой:

var lvl:Level = EXTJsonSerialization.decode(text, Level);

В итоге, в переменной lvl мы имеем нашу иерархию классов без dynamic’ов и безликих object’ов .

Остается только дописать сохранение файлов, но это уже в другой раз, если кому-то интересно.