writeJSON

write a jsonizeable object to a file

void
writeJSON
(
T
)
(
T obj
,
string file
)

Examples

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);

Meta