When EJSON calls the JSONValue of your Outer type, it does not recurs to the result to automatically determine the internal types. Similarly, from the JSONValue function (the function that you pass to the EJSON.addType method), you get a JSON value object (the result of whatever is returned by the JSONValue function), and you can do something about it. To better understand the conversion process, go through an example based on your classes.
Let's say we are going to pass an instance of your Outer class through wiring (for example, as a parameter in a method call).
myOuter = new Outer({innerHere: new Inner('inner value')});
The meteor will follow steps similar to:
EJSON.stringify(myOuter) => var jsonValue = EJSON.toJSONValue(myOuter); var json = JSON.stringify(jsonValue);
In the EJSON.toJSONValue call, a new object is created with the property $ type and $ value. The value of $ value is the result of calling the JSONValue function on your object. So jsonValue is an object that looks like this:
{ $type: 'Outer', $value: { innerHere: { value: 'inner value' } } }
Calling JSON.stringify (jsonValue) results in a JSON string that looks like this:
"{"$type":"Outer","$value":{"value":{"innerHere":{"value":"inner value"}}}}"
If you want the innerHere property to be an EJSON type, we also need to call EJSON.toJSONValue on this object (from the Outer toJSONValue method). For example (in js):
Outer.prototype.toJSONValue = function () { return { value: EJSON.toJSONValue(this.value) }; };
Now suppose we create a new Outer instance as follows:
myOuter = new Outer(new Inner('inner value'));
And then we call EJSON.toJSONValue (myOuter):
{ $type: 'Outer', $value: { value: { $type: 'Inner', $value: { value: 'inner value' } } } }
And the resulting json string, which is sent over the wire, looks like this:
"{"$type":"Outer","$value":{"value":{"$type":"Inner","$value":{"value":"inner value"}}}}"
Ok, now what happens in our JSONValue function? We are going to get an object similar to the one returned by the JSONValue function. Therefore, we need to call EJSON.fromJSONValue for each of the properties, which we know are custom types, before passing them to the Outer constructor. In this example, you can do the following:
EJSON.addType('Outer', function (jsonValue) { var inner = EJSON.fromJSONValue(jsonValue.value); return new Outer(inner); });
Two methods you can use to test serialization and deserialization:
var serialized = EJSON.stringify(myOuter); var deserialized = EJSON.parse(serialized);
Hope this helps!