For client-server
communications we increasingly use JSON to communicate objects. As our client
code grows more complex we send richer and richer objects. One issue is that
when you serialize to JSON and then deserialize on the client you lose object
relationships. For example, let's say I send a List<Albums> but I also
send a FavoriteAlbum. Now in code the actual Album object may be pointed to by
the list and by FavoriteAlbum. It is a single object, but when you convert it
to JSON it becomes two objects.
So JSON.Net has
already solved this problem with "PreserveReferenceHandling". It
attaches an $id property to every object and objects that are references to
previously serialized objects have a $ref property and nothing else. This
allows you to accurately represent non-trivial sets of object relationships.
The issue I ran into
is that I didn't see any automatic tools for handling this. In using SignalR I
found that SignalR automatically did JSON deserialization, but ignored the
whole scheme of $id and $ref, so I put together some code to use these 'hints' to
correctly build the right structure of the client. This code is happy path
right now and it is dependent, somewhat unnecessarily, on Jquery. It also
hasn't been tuned for performance, but I think it is a good start and is fine
for prototyping.
var
JSONPointerParse = (function ($) {
var hashOfObjects = {};
var collectIds = function (obj) {
if ($.type(obj) === "object") {
if (obj.hasOwnProperty("$id")) {
hashOfObjects[obj.$id] = obj;
}
for (var prop in obj) {
collectIds(obj[prop]);
}
} else if ($.type(obj) === "array") {
obj.forEach(function (element) {
collectIds(element);
});
}
};
var setReferences = function (obj) {
if ($.type(obj) === "object") {
for (var prop in obj) {
if ($.type(obj[prop]) === "object" &&
obj[prop].hasOwnProperty("$ref")) {
obj[prop] = hashOfObjects[obj[prop]["$ref"]];
} else {
setReferences(obj[prop]);
}
}
} else if ($.type(obj) === "array") {
obj.forEach(function (element, index, array) {
if ($.type(element) === "object" &&
element.hasOwnProperty("$ref")) {
array[index] = hashOfObjects[element["$ref"]];
} else {
setReferences(element);
}
});
}
};
var pointerParse = function (obj) {
hashOfObjects = {};
collectIds(obj);
setReferences(obj);
};
return { Run: pointerParse };
})(jQuery);
Do you have a github page for this? If not it is ok I will create one based on the slight modifications I made to your code.
ReplyDelete