我正在尝试将JSON字符串反序列化为Haxe中的类实例。
class Action
{
public var id:Int;
public var name:String;
public function new(id:Int, name:String)
{
this.id = id;
this.name = name;
}
}
我想做这样的事情:
var action:Action = haxe.Json.parse(actionJson);
trace(action.name);
然而,这会产生错误:
TypeError:错误#1034:类型强制失败:无法将Object @ 3431809转换为Action
答案 0 :(得分:4)
Json没有映射语言特定数据类型的机制,只支持JS中包含的数据类型的子集。要保留有关Haxe类型的信息,您当然可以建立自己的机制。
// 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));
}
}
}
答案 1 :(得分:3)
我扩展Franco's answer以允许递归地包含json对象中的对象,只要在该对象上设置_explicitType
属性。
例如,以下json:
{
intPropertyExample : 5,
stringPropertyExample : 'my string',
pointPropertyExample : {
_explicitType : 'flash.geom.Point',
x : 5,
y : 6
}
}
将被正确地序列化为一个类如下所示的对象:
import flash.geom.Point;
class MyTestClass
{
public var intPropertyExample:Int;
public var stringPropertyExample:String;
public var pointPropertyExample:Point;
}
致电时:
var serializedObject:MyTestClass = EXTJsonSerialization.decode([string of json above], MyTestClass)
以下是代码(请注意,它使用TJSON作为解析器,建议使用CrazySam):
import tjson.TJSON;
class EXTJsonSerialization
{
public static function encode(o : Dynamic)
{
return TJSON.encode(o);
}
public static function decode<T>(s : String, typeClass : Class<Dynamic>) : T
{
var o = TJSON.parse(s);
var inst = Type.createEmptyInstance(typeClass);
EXTJsonSerialization.populate(inst, o);
return inst;
}
private static function populate(inst, data)
{
for (field in Reflect.fields(data))
{
if (field == "_explicitType")
continue;
var value = Reflect.field(data, field);
var valueType = Type.getClass(value);
var valueTypeString:String = Type.getClassName(valueType);
var isValueObject:Bool = Reflect.isObject(value) && valueTypeString != "String";
var valueExplicitType:String = null;
if (isValueObject)
{
valueExplicitType = Reflect.field(value, "_explicitType");
if (valueExplicitType == null && valueTypeString == "Array")
valueExplicitType = "Array";
}
if (valueExplicitType != null)
{
var fieldInst = Type.createEmptyInstance(Type.resolveClass(valueExplicitType));
populate(fieldInst, value);
Reflect.setField(inst, field, fieldInst);
}
else
{
Reflect.setField(inst, field, value);
}
}
}
}
答案 2 :(得分:0)
为此目的,现代的基于宏的库是json2object。可以这样使用:
var parser = new json2object.JsonParser<Action>();
var action:Action = parser.fromJson('{"id": 0, "name": "run"}', "action.json");
tink_json是另一个宏供电的选项。在这种情况下,它有点冗长,因为它要求您指定如何使用@:jsonParse
metadata解析类:
@:jsonParse(function(json) return new Action(json.id, json.name))
class Action {
// ...
解析是单线的:
var action:Action = tink.Json.parse('{"id": 0, "name": "run"}');