Stack overflow

This commit is contained in:
Tobe O 2018-08-11 15:07:35 -04:00
parent 24b03ce71c
commit a570537bac
6 changed files with 165 additions and 24 deletions

View file

@ -16,13 +16,17 @@ class Container {
var named = <String, dynamic>{}; var named = <String, dynamic>{};
if (reflectedType is ReflectedClass) { if (reflectedType is ReflectedClass) {
bool isDefault(String name) {
return name.isEmpty || name == reflectedType.name;
}
var constructor = reflectedType.constructors.firstWhere( var constructor = reflectedType.constructors.firstWhere(
(c) => c.name.isEmpty, (c) => isDefault(c.name),
orElse: () => throw new ReflectionException('${reflectedType orElse: () => throw new ReflectionException(
.name} has no default constructor, and therefore cannot be instantiated.')); '${reflectedType.name} has no default constructor, and therefore cannot be instantiated.'));
for (var param in constructor.parameters) { for (var param in constructor.parameters) {
var value = make(param.type); var value = make(param.type.reflectedType);
if (param.isNamed) { if (param.isNamed) {
named[param.name] = value; named[param.name] = value;
@ -31,8 +35,10 @@ class Container {
} }
} }
return reflectedType return reflectedType.newInstance(
.newInstance(constructor.name, positional, named, []); isDefault(constructor.name) ? '' : constructor.name,
positional,
named, []);
} else { } else {
throw new ReflectionException( throw new ReflectionException(
'$type is not a class, and therefore cannot be instantiated.'); '$type is not a class, and therefore cannot be instantiated.');
@ -42,8 +48,8 @@ class Container {
void singleton(Object object, {Type as}) { void singleton(Object object, {Type as}) {
if (_singletons.containsKey(as ?? object.runtimeType)) { if (_singletons.containsKey(as ?? object.runtimeType)) {
throw new StateError('This container already has a singleton for ${as ?? throw new StateError(
object.runtimeType}.'); 'This container already has a singleton for ${as ?? object.runtimeType}.');
} }
_singletons[as ?? object.runtimeType] = object; _singletons[as ?? object.runtimeType] = object;

View file

@ -1,9 +1,14 @@
import 'dart:mirrors' as dart; import 'dart:mirrors' as dart;
import 'package:angel_container/angel_container.dart'; import 'package:angel_container/angel_container.dart';
import 'package:angel_container/src/reflector.dart'; import 'package:angel_container/src/reflector.dart';
import 'package:angel_container/src/reflector.dart';
/// A [Reflector] implementation that forwards to `dart:mirrors`.
///
/// Useful on the server, where reflection is supported.
class MirrorsReflector implements Reflector { class MirrorsReflector implements Reflector {
const MirrorsReflector();
@override @override
String getName(Symbol symbol) => dart.MirrorSystem.getName(symbol); String getName(Symbol symbol) => dart.MirrorSystem.getName(symbol);
@ -20,7 +25,8 @@ class MirrorsReflector implements Reflector {
@override @override
ReflectedFunction reflectFunction(Function function) { ReflectedFunction reflectFunction(Function function) {
// TODO: implement reflectFunction var closure = dart.reflect(function) as dart.ClosureMirror;
return new _ReflectedMethodMirror(closure.function);
} }
@override @override
@ -33,6 +39,11 @@ class MirrorsReflector implements Reflector {
return new _ReflectedTypeMirror(mirror); return new _ReflectedTypeMirror(mirror);
} }
} }
@override
ReflectedInstance reflectInstance(Object object) {
return new _ReflectedInstanceMirror(object);
}
} }
class _ReflectedTypeParameter extends ReflectedTypeParameter { class _ReflectedTypeParameter extends ReflectedTypeParameter {
@ -52,6 +63,7 @@ class _ReflectedTypeMirror extends ReflectedType {
mirror.typeVariables mirror.typeVariables
.map((m) => new _ReflectedTypeParameter(m)) .map((m) => new _ReflectedTypeParameter(m))
.toList(), .toList(),
mirror.reflectedType,
); );
@override @override
@ -61,7 +73,7 @@ class _ReflectedTypeMirror extends ReflectedType {
@override @override
T newInstance<T>(String constructorName, List positionalArguments, T newInstance<T>(String constructorName, List positionalArguments,
Map<String, dynamic> namedArguments, List<Type> typeArguments) { [Map<String, dynamic> namedArguments, List<Type> typeArguments]) {
throw new ReflectionException( throw new ReflectionException(
'$name is not a class, and therefore cannot be instantiated.'); '$name is not a class, and therefore cannot be instantiated.');
} }
@ -79,6 +91,7 @@ class _ReflectedClassMirror extends ReflectedClass {
mirror.metadata.map((m) => new _ReflectedInstanceMirror(m)).toList(), mirror.metadata.map((m) => new _ReflectedInstanceMirror(m)).toList(),
_constructorsOf(mirror), _constructorsOf(mirror),
_declarationsOf(mirror), _declarationsOf(mirror),
mirror.reflectedType,
); );
static List<ReflectedFunction> _constructorsOf(dart.ClassMirror mirror) { static List<ReflectedFunction> _constructorsOf(dart.ClassMirror mirror) {
@ -86,6 +99,10 @@ class _ReflectedClassMirror extends ReflectedClass {
for (var key in mirror.declarations.keys) { for (var key in mirror.declarations.keys) {
var value = mirror.declarations[key]; var value = mirror.declarations[key];
if (value is dart.MethodMirror && value.isConstructor) {
out.add(new _ReflectedMethodMirror(value));
}
} }
return out; return out;
@ -96,6 +113,11 @@ class _ReflectedClassMirror extends ReflectedClass {
for (var key in mirror.declarations.keys) { for (var key in mirror.declarations.keys) {
var value = mirror.declarations[key]; var value = mirror.declarations[key];
if (value is dart.MethodMirror && !value.isConstructor) {
out.add(new ReflectedDeclaration(dart.MirrorSystem.getName(key),
value.isStatic, new _ReflectedMethodMirror(value)));
}
} }
return out; return out;
@ -108,8 +130,10 @@ class _ReflectedClassMirror extends ReflectedClass {
@override @override
T newInstance<T>(String constructorName, List positionalArguments, T newInstance<T>(String constructorName, List positionalArguments,
Map<String, dynamic> namedArguments, List<Type> typeArguments) { [Map<String, dynamic> namedArguments, List<Type> typeArguments]) {
// TODO: implement newInstance return mirror
.newInstance(new Symbol(constructorName), positionalArguments)
.reflectee as T;
} }
} }
@ -125,3 +149,31 @@ class _ReflectedInstanceMirror extends ReflectedInstance {
return mirror.delegate(invocation) as T; return mirror.delegate(invocation) as T;
} }
} }
class _ReflectedMethodMirror extends ReflectedFunction {
final dart.MethodMirror mirror;
_ReflectedMethodMirror(this.mirror)
: super(
dart.MirrorSystem.getName(mirror.simpleName),
<ReflectedTypeParameter>[],
mirror.metadata
.map((mirror) => new _ReflectedInstanceMirror(mirror))
.toList(),
const MirrorsReflector()
.reflectType(mirror.returnType.reflectedType),
mirror.parameters.map(_reflectParameter).toList(),
mirror.isGetter,
mirror.isSetter);
static ReflectedParameter _reflectParameter(dart.ParameterMirror mirror) {
return new ReflectedParameter(
dart.MirrorSystem.getName(mirror.simpleName),
mirror.metadata
.map((mirror) => new _ReflectedInstanceMirror(mirror))
.toList(),
const MirrorsReflector().reflectType(mirror.type.reflectedType),
!mirror.isOptional,
mirror.isNamed);
}
}

View file

@ -1,5 +1,5 @@
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:quiver_hashcode/hashcode.dart'; import 'package:quiver/core.dart';
abstract class Reflector { abstract class Reflector {
String getName(Symbol symbol); String getName(Symbol symbol);
@ -9,6 +9,8 @@ abstract class Reflector {
ReflectedFunction reflectFunction(Function function); ReflectedFunction reflectFunction(Function function);
ReflectedType reflectType(Type type); ReflectedType reflectType(Type type);
ReflectedInstance reflectInstance(Object object);
} }
abstract class ReflectedInstance { abstract class ReflectedInstance {
@ -30,21 +32,23 @@ abstract class ReflectedInstance {
abstract class ReflectedType { abstract class ReflectedType {
final String name; final String name;
final List<ReflectedTypeParameter> typeParameters; final List<ReflectedTypeParameter> typeParameters;
final Type reflectedType;
const ReflectedType(this.name, this.typeParameters); const ReflectedType(this.name, this.typeParameters, this.reflectedType);
@override @override
int get hashCode => hash2(name, typeParameters); int get hashCode => hash3(name, typeParameters, reflectedType);
@override @override
bool operator ==(other) => bool operator ==(other) =>
other is ReflectedType && other is ReflectedType &&
other.name == name && other.name == name &&
const ListEquality<ReflectedTypeParameter>() const ListEquality<ReflectedTypeParameter>()
.equals(other.typeParameters, typeParameters); .equals(other.typeParameters, typeParameters) &&
other.reflectedType == reflectedType;
T newInstance<T>(String constructorName, List positionalArguments, T newInstance<T>(String constructorName, List positionalArguments,
Map<String, dynamic> namedArguments, List<Type> typeArguments); [Map<String, dynamic> namedArguments, List<Type> typeArguments]);
bool isAssignableTo(ReflectedType other); bool isAssignableTo(ReflectedType other);
} }
@ -54,9 +58,14 @@ abstract class ReflectedClass extends ReflectedType {
final List<ReflectedFunction> constructors; final List<ReflectedFunction> constructors;
final List<ReflectedDeclaration> declarations; final List<ReflectedDeclaration> declarations;
const ReflectedClass(String name, List<ReflectedTypeParameter> typeParameters, const ReflectedClass(
this.annotations, this.constructors, this.declarations) String name,
: super(name, typeParameters); List<ReflectedTypeParameter> typeParameters,
this.annotations,
this.constructors,
this.declarations,
Type reflectedType)
: super(name, typeParameters, reflectedType);
@override @override
int get hashCode => int get hashCode =>
@ -96,7 +105,7 @@ class ReflectedFunction {
final String name; final String name;
final List<ReflectedTypeParameter> typeParameters; final List<ReflectedTypeParameter> typeParameters;
final List<ReflectedInstance> annotations; final List<ReflectedInstance> annotations;
final Type returnType; final ReflectedType returnType;
final List<ReflectedParameter> parameters; final List<ReflectedParameter> parameters;
final bool isGetter, isSetter; final bool isGetter, isSetter;
@ -132,7 +141,7 @@ class ReflectedFunction {
class ReflectedParameter { class ReflectedParameter {
final String name; final String name;
final List<ReflectedInstance> annotations; final List<ReflectedInstance> annotations;
final Type type; final ReflectedType type;
final bool isRequired; final bool isRequired;
final bool isNamed; final bool isNamed;

View file

@ -1,4 +1,12 @@
name: angel_container name: angel_container
version: 1.0.0-alpha
author: Tobe O <thosakwe@gmail.com>
description: "A better IoC container for Angel, ultimately allowing Angel to be used without dart:mirrors."
homepage: https://github.com/angel-dart/container.git
environment:
sdk: ">=1.8.0 <3.0.0"
dependencies: dependencies:
collection: ^1.0.0 collection: ^1.0.0
quiver_hashcode: ^1.0.0 quiver: ^2.0.0
dev_dependencies:
test:

View file

@ -0,0 +1,59 @@
import 'package:angel_container/angel_container.dart';
import 'package:test/test.dart';
void testReflector(Reflector reflector) {
var blaziken = new Pokemon('Blaziken', PokemonType.fire);
Container container;
setUp(() {
container = new Container(reflector);
container.singleton(blaziken);
});
test('make on singleton type returns singleton', () {
expect(container.make(Pokemon), blaziken);
});
test('make on aliased singleton returns singleton', () {
container.singleton(blaziken, as: StateError);
expect(container.make(StateError), blaziken);
});
test('constructor injects singleton', () {
var lower = container.make(LowerPokemon) as LowerPokemon;
expect(lower.lowercaseName, blaziken.name.toLowerCase());
});
test('newInstance works', () {
var type = container.reflector.reflectType(Pokemon);
var instance =
type.newInstance('changeName', [blaziken, 'Charizard']) as Pokemon;
print(instance);
expect(instance.name, 'Charizard');
expect(instance.type, PokemonType.fire);
});
}
class LowerPokemon {
final Pokemon pokemon;
LowerPokemon(this.pokemon);
String get lowercaseName => pokemon.name.toLowerCase();
}
class Pokemon {
final String name;
final PokemonType type;
Pokemon(this.name, this.type);
factory Pokemon.changeName(Pokemon other, String name) {
return new Pokemon(name, other.type);
}
@override
String toString() => 'NAME: $name, TYPE: $type';
}
enum PokemonType { water, fire, grass, ice, poison, flying }

View file

@ -0,0 +1,7 @@
import 'package:angel_container/mirrors.dart';
import 'common.dart';
void main() {
testReflector(const MirrorsReflector());
}