json conversion of primitive types
import std.math : approxEqual; enum Category { one, two } auto j1 = toJSON("bork"); assert(j1.type == JSON_TYPE.STRING && j1.str == "bork"); assert(extract!string(j1) == "bork"); auto j2 = toJSON(4.1); assert(j2.type == JSON_TYPE.FLOAT && j2.floating.approxEqual(4.1)); assert(extract!float(j2).approxEqual(4.1)); assert(extract!double(j2).approxEqual(4.1)); assert(extract!real(j2).approxEqual(4.1)); auto j3 = toJSON(41); assert(j3.type == JSON_TYPE.INTEGER && j3.integer == 41); assert(extract!int(j3) == 41); assert(extract!long(j3) == 41); auto j4 = toJSON(41u); assert(j4.type == JSON_TYPE.UINTEGER && j4.uinteger == 41u); assert(extract!uint(j4) == 41u); assert(extract!ulong(j4) == 41u); auto jenum = toJSON!Category(Category.one); assert(jenum.type == JSON_TYPE.STRING); assert(jenum.extract!Category == Category.one); // homogenous json array auto j5 = toJSON([9, 8, 7, 6]); assert(j5.array[0].integer == 9); assert(j5.array[1].integer == 8); assert(j5.array[2].integer == 7); assert(j5.array[3].integer == 6); assert(j5.type == JSON_TYPE.ARRAY); assert(extract!(int[])(j5) == [9, 8, 7, 6]); // heterogenous json array auto j6 = toJSON("sammich", 1.5, 2, 3u); assert(j6.array[0].str == "sammich"); assert(j6.array[1].floating.approxEqual(1.5)); assert(j6.array[2].integer == 2); assert(j6.array[3].uinteger == 3u); // associative array int[string] aa = ["a" : 1, "b" : 2, "c" : 3]; auto j7 = toJSON(aa); assert(j7.type == JSON_TYPE.OBJECT); assert(j7.object["a"].integer == 1); assert(j7.object["b"].integer == 2); assert(j7.object["c"].integer == 3); assert(extract!(int[string])(j7) == aa); assert(j7.extract!int("b") == 2);
object serialization -- fields only
1 import std.math : approxEqual; 2 3 static class Fields { 4 this() { } // class must have a no-args ctor 5 6 this(int iVal, float fVal, string sVal, int[] aVal, string noJson) { 7 i = iVal; 8 f = fVal; 9 s = sVal; 10 a = aVal; 11 dontJsonMe = noJson; 12 } 13 14 mixin JsonizeMe; 15 16 @jsonize { // fields to jsonize -- test different access levels 17 public int i; 18 protected float f; 19 public int[] a; 20 private string s; 21 } 22 string dontJsonMe; 23 24 override bool opEquals(Object o) { 25 auto other = cast(Fields) o; 26 return i == other.i && s == other.s && a == other.a && f.approxEqual(other.f); 27 } 28 } 29 30 auto obj = new Fields(1, 4.2, "tally ho!", [9, 8, 7, 6], "blarg"); 31 auto json = toJSON!Fields(obj); 32 33 assert(json.object["i"].integer == 1); 34 assert(json.object["f"].floating.approxEqual(4.2)); 35 assert(json.object["s"].str == "tally ho!"); 36 assert(json.object["a"].array[0].integer == 9); 37 assert("dontJsonMe" !in json.object); 38 39 // reconstruct from json 40 auto r = extract!Fields(json); 41 assert(r.i == 1); 42 assert(r.f.approxEqual(4.2)); 43 assert(r.s == "tally ho!"); 44 assert(r.a == [9, 8, 7, 6]); 45 assert(r.dontJsonMe is null); 46 47 // array of objects 48 auto a = [ 49 new Fields(1, 4.2, "tally ho!", [9, 8, 7, 6], "blarg"), 50 new Fields(7, 42.2, "yea merrily", [1, 4, 6, 4], "asparagus") 51 ]; 52 53 // serialize array of user objects to json 54 auto jsonArray = toJSON!(Fields[])(a); 55 // reconstruct from json 56 assert(extract!(Fields[])(jsonArray) == a);
object serialization with properties
import std.math : approxEqual; static class Props { this() { } // class must have a no-args ctor this(int iVal, float fVal, string sVal, string noJson) { _i = iVal; _f = fVal; _s = sVal; _dontJsonMe = noJson; } mixin JsonizeMe; @property { // jsonize ref property accessing private field @jsonize ref int i() { return _i; } // jsonize property with non-trivial get/set methods @jsonize float f() { return _f - 3; } // the jsonized value will equal _f - 3 float f(float val) { return _f = val + 5; } // 5 will be added to _f when retrieving from json // don't jsonize these properties ref string s() { return _s; } ref string dontJsonMe() { return _dontJsonMe; } } private: int _i; float _f; @jsonize string _s; string _dontJsonMe; } auto obj = new Props(1, 4.2, "tally ho!", "blarg"); auto json = toJSON(obj); assert(json.object["i"].integer == 1); assert(json.object["f"].floating.approxEqual(4.2 - 3.0)); // property should have subtracted 3 on retrieval assert(json.object["_s"].str == "tally ho!"); assert("dontJsonMe" !in json.object); auto r = extract!Props(json); assert(r.i == 1); assert(r._f.approxEqual(4.2 - 3.0 + 5.0)); // property accessor should add 5 assert(r._s == "tally ho!"); assert(r.dontJsonMe is null);
object serialization with custom constructor
import std.math : approxEqual; static class Custom { mixin JsonizeMe; this(int i) { _i = i; _s = "something"; _f = 10.2; } @jsonize this(int _i, string _s, float _f = 20.2) { this._i = _i; this._s = _s ~ " jsonized"; this._f = _f; } @jsonize this(double d) { // alternate ctor _f = d.to!float; _s = d.to!string; _i = d.to!int; } private: @jsonize { string _s; float _f; int _i; } } auto c = new Custom(12); auto json = toJSON(c); assert(json.object["_i"].integer == 12); assert(json.object["_s"].str == "something"); assert(json.object["_f"].floating.approxEqual(10.2)); auto c2 = extract!Custom(json); assert(c2._i == 12); assert(c2._s == "something jsonized"); assert(c2._f.approxEqual(10.2)); // test alternate ctor json = parseJSON(`{"d" : 5}`); c = json.extract!Custom; assert(c._f.approxEqual(5) && c._i == 5 && c._s == "5");
struct serialization
import std.math : approxEqual; static struct S { mixin JsonizeMe; @jsonize { int x; float f; string s; } int dontJsonMe; this(int x, float f, string s, int noJson) { this.x = x; this.f = f; this.s = s; this.dontJsonMe = noJson; } } auto s = S(5, 4.2, "bogus", 7); auto json = toJSON(s); // serialize a struct assert(json.object["x"].integer == 5); assert(json.object["f"].floating.approxEqual(4.2)); assert(json.object["s"].str == "bogus"); assert("dontJsonMe" !in json.object); auto r = extract!S(json); assert(r.x == 5); assert(r.f.approxEqual(4.2)); assert(r.s == "bogus"); assert(r.dontJsonMe == int.init);
json file I/O
enum file = "test.json"; scope(exit) remove(file); static struct Data { mixin JsonizeMe; @jsonize { int x; string s; float f; } } // write an array of user-defined structs auto array = [Data(5, "preposterous", 12.7), Data(8, "tesseract", -2.7), Data(5, "baby sloths", 102.7)]; writeJSON(array, file); auto readBack = readJSON!(Data[])(file); assert(readBack == array); // now try an associative array auto aa = ["alpha": Data(27, "yams", 0), "gamma": Data(88, "spork", -99.999)]; writeJSON(aa, file); auto aaReadBack = readJSON!(Data[string])(file); assert(aaReadBack == aa);
inheritance
import std.math : approxEqual; static class Parent { mixin JsonizeMe; @jsonize { int x; string s; } } static class Child : Parent { mixin JsonizeMe; @jsonize { float f; } } auto c = new Child; c.x = 5; c.s = "hello"; c.f = 2.1; auto json = c.toJSON; assert(json.extract!int("x") == 5); assert(json.extract!string("s") == "hello"); assert(json.extract!float("f").approxEqual(2.1)); auto child = json.extract!Child; assert(child.x == 5 && child.s == "hello" && child.f.approxEqual(2.1)); auto parent = json.extract!Parent; assert(parent.x == 5 && parent.s == "hello");
inheritance with ctors
import std.math : approxEqual; static class Parent { mixin JsonizeMe; @jsonize this(int x, string s) { _x = x; _s = s; } @jsonize @property { int x() { return _x; } string s() { return _s; } } private: int _x; string _s; } static class Child : Parent { mixin JsonizeMe; @jsonize this(int x, string s, float f) { super(x, s); _f = f; } @jsonize @property { float f() { return _f; } } private: float _f; } auto c = new Child(5, "hello", 2.1); auto json = c.toJSON; assert(json.extract!int("x") == 5); assert(json.extract!string("s") == "hello"); assert(json.extract!float("f").approxEqual(2.1)); auto child = json.extract!Child; assert(child.x == 5 && child.s == "hello" && child.f.approxEqual(2.1)); auto parent = json.extract!Parent; assert(parent.x == 5 && parent.s == "hello");
renamed members
static class Bleh { mixin JsonizeMe; private { @jsonize("x") int _x; @jsonize("s") string _s; } } auto b = new Bleh; b._x = 5; b._s = "blah"; auto json = b.toJSON; assert(json.extract!int("x") == 5); assert(json.extract!string("s") == "blah"); auto reconstruct = json.extract!Bleh; assert(reconstruct._x == b._x && reconstruct._s == b._s);
write a jsonizeable object to a file