diff --git a/lib/src/exception/Exception.dart b/lib/src/exception/Exception.dart index 8f7d883..21f3861 100644 --- a/lib/src/exception/Exception.dart +++ b/lib/src/exception/Exception.dart @@ -13,6 +13,7 @@ export 'package:Q/src/exception/RequiredFieldNotFoundException.dart'; export 'package:Q/src/exception/RequiredMethodNotFoundException.dart'; export 'package:Q/src/exception/RouterNotFoundException.dart'; export 'package:Q/src/exception/RouterNotFoundOfRouterChainException.dart'; +export 'package:Q/src/exception/SideEffectModelReflectFunctionParameterNotMatchClassFieldException.dart'; export 'package:Q/src/exception/SizeUnitParseException.dart'; export 'package:Q/src/exception/TimeUnitParseException.dart'; export 'package:Q/src/exception/UnExpectedRequestApplicationJsonException.dart'; diff --git a/lib/src/exception/RequiredInitialValueMustBeProvidedException.dart b/lib/src/exception/RequiredInitialValueMustBeProvidedException.dart new file mode 100644 index 0000000..a3a348b --- /dev/null +++ b/lib/src/exception/RequiredInitialValueMustBeProvidedException.dart @@ -0,0 +1,17 @@ +class RequiredInitialValueMustBeProvidedException extends Exception { + factory RequiredInitialValueMustBeProvidedException({String message, String name}) => + _RequiredInitialValueMustBeProvidedException(message: message, name: name); +} + +class _RequiredInitialValueMustBeProvidedException implements RequiredInitialValueMustBeProvidedException { + final message; + + final String name; + + _RequiredInitialValueMustBeProvidedException({this.message, this.name}); + + String toString() { + if (message == null) return "Exception: required initial value must be provided: '${this.name}'"; + return "Exception: $message"; + } +} diff --git a/lib/src/exception/SideEffectModelReflectFunctionParameterNotMatchClassFieldException.dart b/lib/src/exception/SideEffectModelReflectFunctionParameterNotMatchClassFieldException.dart new file mode 100644 index 0000000..e43a5c6 --- /dev/null +++ b/lib/src/exception/SideEffectModelReflectFunctionParameterNotMatchClassFieldException.dart @@ -0,0 +1,18 @@ +class SideEffectModelReflectFunctionParameterNotMatchClassFieldException extends Exception { + factory SideEffectModelReflectFunctionParameterNotMatchClassFieldException({String message, String name}) => + _SideEffectModelReflectFunctionParameterNotMatchClassFieldException(message: message, name: name); +} + +class _SideEffectModelReflectFunctionParameterNotMatchClassFieldException + implements SideEffectModelReflectFunctionParameterNotMatchClassFieldException { + final message; + + final String name; + + _SideEffectModelReflectFunctionParameterNotMatchClassFieldException({this.message, this.name}); + + String toString() { + if (message == null) return "Exception: The field named: '${this.name}' not found."; + return "Exception: $message"; + } +} diff --git a/lib/src/helpers/reflect/ClassTransformer.dart b/lib/src/helpers/reflect/ClassTransformer.dart index e1322c1..0d7cfb3 100644 --- a/lib/src/helpers/reflect/ClassTransformer.dart +++ b/lib/src/helpers/reflect/ClassTransformer.dart @@ -2,6 +2,7 @@ import 'dart:mirrors'; import 'package:Q/Q.dart'; import 'package:Q/src/exception/RequiredAnnotationNotFoundException.dart'; +import 'package:Q/src/exception/RequiredInitialValueMustBeProvidedException.dart'; import 'package:Q/src/utils/SymbolUtil.dart'; class ClassTransformer { @@ -9,6 +10,7 @@ class ClassTransformer { static dynamic fromMap(Map data, Type clazz) { ClassMirror classMirror = reflectClass(clazz); + InstanceMirror instanceMirror = classMirror.newInstance(Symbol.empty, []); InstanceMirror sideEffectModelMirror = classMirror.metadata.firstWhere((InstanceMirror instanceMirror) { return instanceMirror.type == reflectClass(SideEffectModel); }); @@ -16,20 +18,9 @@ class ClassTransformer { InstanceMirror func = sideEffectModelMirror.getField(Symbol(FUNC_FIELD)); if (func != null) { FunctionTypeMirror functionTypeMirror = func.type; - List positionalParameters = List.from(functionTypeMirror.parameters.where((ParameterMirror parameterMirror) { - return !parameterMirror.isOptional && !parameterMirror.isNamed; - })); - List namedParameters = List.from(functionTypeMirror.parameters.where((ParameterMirror parameterMirror) { - return parameterMirror.isNamed; - })); - List positionalArguments = List.from(positionalParameters.map((ParameterMirror parameterMirror) { - return reflectParameterValue(data, parameterMirror); - })); - Map namedArguments = Map(); - namedParameters.forEach((ParameterMirror parameterMirror) { - namedArguments[parameterMirror.simpleName] = reflectParameterValue(data, parameterMirror); + functionTypeMirror.parameters.forEach((ParameterMirror parameterMirror) { + instanceMirror.setField(parameterMirror.simpleName, reflectParameterValue(data, parameterMirror, instanceMirror)); }); - return Function.apply(func.reflectee, positionalArguments, Map.from(namedArguments)); } else { throw RequiredFieldNotFoundException(name: FUNC_FIELD); } @@ -42,7 +33,6 @@ class ClassTransformer { } Model model = modelAnnotationMirror.reflectee; Map rules = model.rules; - InstanceMirror instanceMirror = classMirror.newInstance(Symbol.empty, []); for (var key in data.keys) { if (rules.containsKey(key)) { dynamic value = data[key]; @@ -51,11 +41,14 @@ class ClassTransformer { instanceMirror.setField(Symbol(key), value); } } - return instanceMirror.reflectee; } + return instanceMirror.reflectee; } - static dynamic reflectParameterValue(Map data, ParameterMirror parameterMirror) { + static dynamic reflectParameterValue(Map data, ParameterMirror parameterMirror, InstanceMirror instanceMirror) { + if (!instanceMirror.type.declarations.containsKey(parameterMirror.simpleName)) { + throw SideEffectModelReflectFunctionParameterNotMatchClassFieldException(name: SymbolUtil.toChars(parameterMirror.simpleName)); + } for (String key in data.keys) { if (SymbolUtil.toChars(parameterMirror.simpleName) == key) { dynamic value = data[key]; @@ -64,21 +57,20 @@ class ClassTransformer { if (parameterClassMirror == reflectClass(List) || parameterClassMirror == reflectClass(Set)) { Type subType = ReflectHelper.getSubType(parameterType); if (hasModel(subType)) { - /** - * TODO type 'List' is not a subtype of type 'List' - * - * fuck - */ + dynamic initialValue = instanceMirror.getField(Symbol(key)).reflectee; + if (initialValue == null) { + throw RequiredInitialValueMustBeProvidedException(name: key); + } if (parameterClassMirror == reflectClass(List)) { - List collection = parameterClassMirror.newInstance(Symbol.empty, []).reflectee; List.from(value).forEach((dynamic val) { - collection.add(fromMap(val, subType)); + initialValue.add(fromMap(val, subType)); }); - return collection; + return initialValue; } else if (parameterClassMirror == reflectClass(Set)) { - return Set.from(Set.from(value).map((dynamic val) { - return fromMap(val, subType); - })); + Set.from(value).forEach((dynamic val) { + initialValue.add(fromMap(val, subType)); + }); + return initialValue; } } else { return ReflectHelper.reflectCollection(parameterMirror.type.reflectedType, subType, value); diff --git a/lib/src/helpers/reflect/ReflectHelper.dart b/lib/src/helpers/reflect/ReflectHelper.dart index 486568b..d961b52 100644 --- a/lib/src/helpers/reflect/ReflectHelper.dart +++ b/lib/src/helpers/reflect/ReflectHelper.dart @@ -1,5 +1,7 @@ import 'dart:mirrors'; +import 'package:Q/src/utils/SymbolUtil.dart'; + typedef ParameterAnnotationCallback = void Function(ParameterMirror parameterMirror, InstanceMirror instanceMirror); class ReflectHelper { @@ -144,4 +146,15 @@ class ReflectHelper { } }); } + + static DeclarationMirror getDeclaration(Type clazz, String name) { + Map mirrors = reflectClass(clazz).declarations; + Symbol symbol = mirrors.keys.firstWhere((Symbol symbol) { + return SymbolUtil.toChars(symbol) == name; + }); + if (symbol != null) { + return mirrors[symbol]; + } + return null; + } } diff --git a/test/ClassTransformer_test.dart b/test/ClassTransformer_test.dart index cf66601..2dafdba 100644 --- a/test/ClassTransformer_test.dart +++ b/test/ClassTransformer_test.dart @@ -2,9 +2,7 @@ import 'package:Q/Q.dart'; import 'package:Q/src/helpers/reflect/ClassTransformer.dart'; import 'package:test/test.dart'; -Person createPerson(String name, int id, int age, List friends, {List nicknames, List girlFriends}) { - return Person._(name: name, id: id, age: age, friends: friends, nicknames: nicknames, girlFriends: girlFriends); -} +void createPerson(String name, int id, int age, List friends, {List nicknames, List girlFriends}) {} //@Model({'name': String, 'int': int, 'age': num, 'friends': List, 'nicknames': List}) @SideEffectModel(createPerson) @@ -12,17 +10,30 @@ class Person { int id; String name; num age; - List friends; - List nicknames; - List girlFriends; + List friends = List(); + List nicknames = List(); + List girlFriends = List(); + + Person(); Person._({this.name, this.id, this.age, this.friends, this.nicknames, this.girlFriends}); + + @override + String toString() { + return 'Person{id: $id, name: $name, age: $age, friends: $friends, nicknames: $nicknames, girlFriends: $girlFriends}'; + } } void main() { group('ClassTransformer tests', () { test('verify', () async { - Person spiderMan = Person._(name: 'peter'); + Person spiderMan = Person._( + name: 'peter', + id: 10, + age: 17, + friends: [Person._(id: 0, name: 'iron man'), Person._(id: 1, name: 'thor')], + nicknames: ["spider", "kid", 'monkey man'], + girlFriends: [Person._(id: 11, name: 'spider girl')]); dynamic result = await ClassTransformer.fromMap({ "name": "peter", @@ -38,7 +49,7 @@ void main() { ] }, Person); if (result is Person) { - expect(result.name, spiderMan.name); + expect(result.toString(), spiderMan.toString()); } }); });