Skip to content

Commit

Permalink
Merge pull request #21 from ucam-cl-dtg/master
Browse files Browse the repository at this point in the history
Make mirror based conversion of objects work properly
  • Loading branch information
chrisbu committed Mar 21, 2013
2 parents d2a0b00 + aab5d44 commit 9275e9d
Show file tree
Hide file tree
Showing 11 changed files with 116 additions and 69 deletions.
6 changes: 5 additions & 1 deletion lib/json_object.dart
Expand Up @@ -8,6 +8,10 @@
library json_object;

import "dart:json" as JSON;
import "dart:async";
import 'dart:mirrors' as mirrors;

part "src/mirror_based_serializer.dart";

// Set to true to as required
var enableJsonObjectDebugMessages = false;
Expand All @@ -22,7 +26,7 @@ void _log(obj) {
* it uses Dart's mirror system to return a real instance of
* the specified type.
*/
class JsonObject extends Object implements Map, Iterable {
class JsonObject<E> extends Object implements Map, Iterable {
/// The original JSON string
var _jsonString;

Expand Down
90 changes: 54 additions & 36 deletions lib/src/mirror_based_serializer.dart
@@ -1,9 +1,4 @@
library json_object_mirrors;

// part of json_object;
import "dart:json" as JSON;
import "dart:async";
import 'dart:mirrors' as mirrors;
part of json_object;

/// Uses mirror based reflection to convert the object passed in to a string
/// of json. The object passed in may be any object, list or map.
Expand All @@ -12,14 +7,15 @@ Future<String> objectToJson(Object object) {
var completer = new Completer<String>();

var onSuccess = (value) {
print("About to stringify: $value");
_log("About to stringify: $value");
var string = JSON.stringify(value);
completer.complete(string);
};

var onError = (AsyncError error) {
print("JsonObject Future Error: $object");
print("Object: ${object.runtimeType}");
print("Stringified: ${JSON.stringify(object)}");
_log("JsonObject Future Error: $object");
_log("Object: ${object.runtimeType}");
_log("Stringified: ${JSON.stringify(object)}");
completer.completeError(error, error.stackTrace);
};

Expand All @@ -43,10 +39,7 @@ class _KeyValuePair {
Future objectToSerializable(Object object, [key=null]) {
var completer = new Completer();

if (object is num ||
object is bool ||
object is String ||
object == null) {
if (isPrimative(object)) {
_serializeNative(object, completer, key);
}
else if (object is Map) {
Expand All @@ -64,14 +57,25 @@ Future objectToSerializable(Object object, [key=null]) {
return completer.future;
}

bool isPrimative(Object object){
if (object is num ||
object is bool ||
object is String ||
object == null) {
return true;
} else {
return false;
}
}

void _serializeNative(Object object, Completer completer, key) {
print("native: $object");
_log("native: $object");
// "native" object types - just complete with that type
_complete(completer,object,key);
}

void _serializeMap(Map object, Completer completer, key) {
print("map: $object");
_log("map: $object");

// convert the map into a serialized map
// each value in the map may itself be a complex object or a "native" type.
Expand All @@ -97,7 +101,7 @@ void _serializeMap(Map object, Completer completer, key) {
}

void _serializeList(List object, Completer completer, key) {
print("list: $object");
_log("list: $object");

// each item in the list will be an object to serialize.
List<Future> listItemsToComplete = new List<Future>();
Expand All @@ -113,7 +117,7 @@ void _serializeList(List object, Completer completer, key) {
}

void _serializeObject(mirrors.InstanceMirror instanceMirror, Completer completer, key) {
print("object: $instanceMirror");
_log("object: $instanceMirror");
var classMirror = instanceMirror.type;

var resultMap = new Map();
Expand All @@ -122,20 +126,27 @@ void _serializeObject(mirrors.InstanceMirror instanceMirror, Completer completer
// for each getter:
classMirror.getters.forEach((getterKey, getter) {
if (!getter.isPrivate && !getter.isStatic) {
print("getter: ${getter.qualifiedName}");
_log("getter: ${getter.qualifiedName}");
var futureField = instanceMirror.getField(getterKey);
print("got future field: $futureField");

var onGetFutureFieldSuccess = (instanceMirrorField) {
print("Got reflecteee for $getterKey: ${instanceMirrorField.reflectee}");
resultMap[getterKey] = instanceMirrorField.reflectee;
};

_log("got future field: $futureField");

var onGetFutureFieldError = (error) {
print("Error: $error");
completer.complete(error);
_log("Error: $error");
completer.completeError(error);
};


var onGetFutureFieldSuccess = (mirrors.InstanceMirror instanceMirrorField) {
Object reflectee = instanceMirrorField.reflectee;
_log("Got reflectee for $getterKey: ${reflectee}");
if (isPrimative(reflectee)){
resultMap[getterKey] = reflectee;
} else {
Future<String> recursed = objectToJson(reflectee).catchError(onGetFutureFieldError);
recursed.then((json) => resultMap[getterKey] = json);
futuresList.add(recursed);
}
};

futureField.then(onGetFutureFieldSuccess, onError:onGetFutureFieldError);
futuresList.add(futureField);
}
Expand All @@ -145,14 +156,21 @@ void _serializeObject(mirrors.InstanceMirror instanceMirror, Completer completer
classMirror.variables.forEach((varKey, variable) {
if (!variable.isPrivate && !variable.isStatic) {
var futureField = instanceMirror.getField(varKey);

var onGetFutureFieldSuccess = (instanceMirrorField) {
print("Got reflecteee for $varKey: ${instanceMirrorField.reflectee}");
resultMap[varKey] = instanceMirrorField.reflectee;

var onGetFutureFieldError = (error) => completer.completeError(error);

var onGetFutureFieldSuccess = (mirrors.InstanceMirror instanceMirrorField) {
Object reflectee = instanceMirrorField.reflectee;
_log("Got reflectee for $varKey: ${reflectee}");
if (isPrimative(reflectee)){
resultMap[varKey] = reflectee;
} else {
Future<String> recursed = objectToJson(reflectee).catchError(onGetFutureFieldError);
recursed.then((json) => resultMap[varKey] = json);
futuresList.add(recursed);
}
};

var onGetFutureFieldError = (error) => completer.complete(error);

futureField.then(onGetFutureFieldSuccess, onError:onGetFutureFieldError);
futuresList.add(futureField);
}
Expand All @@ -167,7 +185,7 @@ void _serializeObject(mirrors.InstanceMirror instanceMirror, Completer completer

}

void _complete(completer, object, key) {
void _complete(Completer completer, object, key) {
if (key != null) {
completer.complete(new _KeyValuePair(key,object)); // complete, because we can't reflect any deeper
}
Expand Down
17 changes: 6 additions & 11 deletions test/json_object_test.dart
Expand Up @@ -16,20 +16,22 @@ part "test_dartlang_article.dart";
part "test_todo_vo.dart";
part "test_print_list.dart";
part "test_list_serialization.dart";
// part "test_mirrors_serialize.dart";
part "test_mirrors_serialize.dart";
part "test_list.dart";

void _log(obj) {
if (enableJsonObjectDebugMessages) print(obj);
}

void main() {
enableJsonObjectDebugMessages = true;

test('sample data', () {
print(1);
testSampleData(); // passes build 14458
});

group('strong typing', () {
test('new', () {
print(2);
testStrongTyping_new(); // passes build 14458
});

Expand All @@ -39,28 +41,23 @@ void main() {
});

test('json stringify', () {
print(3);
testJsonStringify(); // passes build 8942
});

test('is extendable', () {
print(4);
testIsExtendable(); // passes build 14458
});

test('extend object', () {
print(5);
testExtendObject(); // passes build 14458
});

test('toString', () {
print(6);
testToString(); // passes build 14458
});

group('dartlang article', () {
test('fromJson', () {
print(7);
testDartlangArticle_fromJson(); // passes build 14458
});

Expand All @@ -71,12 +68,10 @@ void main() {
});

test('toTodoVO', () {
print(8);
testTodoVO();
});

test('list', () {
print(9);
testList();
testListIterator();
testPrintList();
Expand All @@ -88,7 +83,7 @@ void main() {



// testMirrorsSerialize(); // tests converting a class to JSON
testMirrorsSerialize(); // tests converting a class to JSON
}


2 changes: 1 addition & 1 deletion test/test_is_extendable.dart
@@ -1,7 +1,7 @@
part of json_object_test;

testIsExtendable() {
print("testIsExtendable");
_log("testIsExtendable");

JsonObject person = new JsonObject();
//isExtendable is currently set to true, so
Expand Down
2 changes: 1 addition & 1 deletion test/test_json_stringify.dart
@@ -1,7 +1,7 @@
part of json_object_test;

testJsonStringify() {
print("testJsonStringify");
_log("testJsonStringify");
JsonObject person = new JsonObject();

// dynamically created some properties
Expand Down
2 changes: 1 addition & 1 deletion test/test_list.dart
Expand Up @@ -9,7 +9,7 @@ testList() {
{"Dis":2222.2,"Flag":0,"Obj":{"ID":2,"Title":"Volvo 240"}}]
""";
MyList list = new MyList.fromString(testJson);
print(list[0].Obj.Title);
_log(list[0].Obj.Title);
expect(list[0].Obj.Title, equals("Volvo 140"));
});

Expand Down

0 comments on commit 9275e9d

Please sign in to comment.