Skip to content

Repository files navigation

json2object - Type safe Haxe/JSON (de)serializer

CI status

This library uses macro and a typed position aware JSON parsing (hxjsonast : https://github.com/nadako/hxjsonast/) to create json parser and writer from and to every supported type.

Incorrect json files or mismatch between the object and the json will yield errors or exceptions, with information on the position of the problematic parts.

Requires at least haxe 3.4.1.

Installation

haxelib install json2object

Usage

Using the parser

varparser=newjson2object.JsonParser<Cls>(); // Creating a parser for Cls classparser.fromJson(jsonString, filename); // Parsing a string. A filename is specified for errors managementvardata:Cls=parser.value; // Access the parsed classvarerrors:Array<json2object.Error> =parser.errors; // Access the potential errors yield during the parsing

It is also possible to populate an existing Array with the errors

varerrors=newArray<json2object.Error>();
vardata:Cls=newjson2object.JsonParser<Cls>(errors).fromJson(jsonString, filename);

To print the errors, you can do

trace(json2object.ErrorUtils.convertErrorArray(parser.errors));

Using the writer

varvalue:Cls;
varwriter=newjson2object.JsonWriter<Cls>(); // Creating a writer for Cls classvarjson=writer.write(value);

The write function accepts an optional String parameter for indenting the json file.

Using the JsonSchema writer

varschema=newjson2object.utils.JsonSchemaWriter<Cls>().schema;

The constructor accepts an optional String parameter for indenting the schema. The generated schema follow null-safety rules.

An other parser json2object.utils.special.VSCodeSchemaWriter has been introduced in 3.6.3 to produce a schema with some non standard properties used by VScode.

Constraints in the parsing

  • Variables defined with the @:jignored metadata will be ignored by the parser.
  • Variables defined with the @:optional metadata won't trigger errors if missing.

Supported types

  • Basic types (Int, Float, Bool, String)
  • Null and Array
  • Map with Int or String keys
  • Class (generics are supported)
  • Anonymous structure
  • Typedef alias of supported types
  • Enum values
  • Abstract over a supported type
  • Abstract enum of String, Int, Float or Bool

Other

  • As of version 2.4.0, the parser fields warnings and object have been replaced by errors and value respectively. Since version 3.6.1, previous notations are no longer supported.

  • Anonymous structure variables can be defined to be loaded with a default value if none is specified in the json using the @:default metadata

typedefStruct= {
varnormal:String;
@:default(newMap<Int, String>())
varmap:Map<Int,String>;
@:default(-1) @:optionalvarid:Int;
}
  • @:default(auto) will, by default, initialize each field of the anonymous structure / object to its default value. No effect on non Structure/Object variables.

  • Variable defined as (default, null) may have unexpected behaviour on some extern classes.

  • You can alias a field from the json into another name, for instance if the field name isn't a valid haxe identifier.

typedefStruct= {
@:alias("public") varisPublic:Bool;
}
classMain {
staticfunctionmain() {
varparser=newJsonParser<Struct>();
vardata=parser.fromJson('{"public": true }', "file.json");
trace(data.isPublic);
}
}

If multiple alias metadatas are on the variable only the last one is taken into account.

  • As of version 3.4.0, private classes can be parsed except on the CS, Java and HL targets.

  • As of version 3.7.0, it is possible to add field or class specific parser/writer to object using the @:jcustomparse / @:jcustomwrite meta. This increase the type coverage of json parsing/writing. Those custom parser/writer can also be applied to the entire class.

    • The custom writer receive a single parameter, the value to stringify
    • The custom parser receive two parameters: the corresponding json, encoded in a hxjsonast.Json instance, and the name of the field being parsed.
    • The @:jcustom* metadatas require the fully quallified path to the custom function, for instance pack.TheClass.fn or pack.TheModule.TheClass.fn
    • As of version 3.8.0 throwing an exception in a custom parser will be available in parser.errors in the CustomFunctionException member.
classObject {
@:jcustomparse(Object.customParse)
@:jcustomwrite(Object.customWrite)
publicvarvalue:Date;
publicfunctionnew() {}
publicstaticfunctioncustomWrite(v:Date):String {
returnv.getTime() +'';
}
publicstaticfunctioncustomParse(val:Json, name:String):Date {
returnswitch (val.value) {
caseJString(s):
Date.fromString(s);
caseJNumber(s):
Date.fromTime(Std.parseFloat(s));
default:
null;
}
}
}

Example

With an anonymous structure:

importjson2object.JsonParser;
classMain {
staticfunctionmain() {
varparser=newJsonParser<{ name:String, quantity:Int }>();
vardata=parser.fromJson('{"name": "computer", "quantity": 2 }', "file.json");
trace(data.name, data.quantity);
}
}

A more complex example with a class and subclass:

importjson2object.JsonParser;
classData {
publicvara:String;
publicvarb:SubData;
publicvard:Array<Int>;
publicvare:Array<Map<String, String>>;
publicvarf:Array<Float>;
publicvarg:Array<Bool>;
@:jignoredpublicvarh:Math;
}
classSubData {
publicvarc:String;
}
classMain {
staticfunctionmain() {
varparser=newJsonParser<Data>();
vardata=parser.fromJson('{"a": "a", "b": {"c": "c"}, "e": [ { "c": "1" }, { "c": "2" } ], "f": [], "g": [ true ] }', "file.json");
varerrors=parser.errors;
trace(data.a);
trace(data.b.c);
for (eindata.e) {
trace(e.get("c"));
}
trace(data.e[0].get("c");
trace(data.f.length);
for (gindata.g) {
trace(data.g.length);
}
for (einerrors) {
switch(e) {
caseIncorrectType(variable, expected, pos):
caseUninitializedVariable(variable, pos):
caseUnknownVariable(variable, pos):
default:
}
}
}
}

About

Type safe Haxe/JSON (de)serializer

Topics

Resources

Stars

74 stars

Watchers

8 watching

Forks

Releases

Packages

Used by

Contributors

Languages