diff --git a/incubation/container/container/lib/src/container.dart b/incubation/container/container/lib/src/container.dart index f6870f5..8aad60a 100644 --- a/incubation/container/container/lib/src/container.dart +++ b/incubation/container/container/lib/src/container.dart @@ -1218,8 +1218,19 @@ class Container { var value = injectAnnotation.reflectee; if (value is Inject) { // Inject specific implementation with config - result.add( - withParameters(value.config, () => make(value.implementation))); + result.add(withParameters(value.config, () { + // First try to make the implementation directly + if (has(value.implementation)) { + return make(value.implementation); + } + // If that fails, try to resolve through contextual binding + var contextual = _getContextualConcrete(value.implementation); + if (contextual != null) { + return make(contextual); + } + // Finally try to make it normally + return make(value.implementation); + })); } else if (value is InjectTagged) { // Inject tagged implementation var tagged = this.tagged(value.tag); @@ -1248,6 +1259,7 @@ class Container { /// Make all instances of a type List makeAll(Type type) { var result = []; + var seen = {}; // Get all tagged implementations var allTags = _tags.entries @@ -1255,8 +1267,38 @@ class Container { .map((entry) => entry.key) .toList(); + // Collect implementations from all tags for (var tag in allTags) { - result.addAll(tagged(tag)); + var implementations = + _tags[tag]!.where((t) => !seen.contains(t)).where((t) { + var reflectedType = reflector.reflectType(t); + var targetType = reflector.reflectType(type); + return reflectedType != null && + targetType != null && + (reflectedType.isAssignableTo(targetType) || t == type); + }).toList(); + + for (var impl in implementations) { + seen.add(impl); + result.add(make(impl)); + } + } + + // If no tagged implementations found, try to get all registered implementations + if (result.isEmpty) { + var allTypes = [..._singletons.keys, ..._factories.keys]; + for (var t in allTypes) { + if (!seen.contains(t)) { + var reflectedType = reflector.reflectType(t); + var targetType = reflector.reflectType(type); + if (reflectedType != null && + targetType != null && + (reflectedType.isAssignableTo(targetType) || t == type)) { + seen.add(t); + result.add(make(t)); + } + } + } } return result; diff --git a/incubation/container/container/test/attribute_binding_test.dart b/incubation/container/container/test/attribute_binding_test.dart index eeb899c..0d18d05 100644 --- a/incubation/container/container/test/attribute_binding_test.dart +++ b/incubation/container/container/test/attribute_binding_test.dart @@ -235,9 +235,19 @@ class MockReflectedClass extends ReflectedType implements ReflectedClass { // Handle List specially if (reflectedType == List) { var loggers = []; - for (var arg in positionalArguments) { - if (arg is Logger) { - loggers.add(arg); + if (positionalArguments.isNotEmpty) { + if (positionalArguments[0] is List) { + for (var item in positionalArguments[0] as List) { + if (item is Logger) { + loggers.add(item); + } + } + } else { + for (var item in positionalArguments) { + if (item is Logger) { + loggers.add(item); + } + } } } return MockReflectedInstance(loggers); @@ -252,18 +262,18 @@ class MockReflectedClass extends ReflectedType implements ReflectedClass { constructor.parameters, positionalArguments, namedArguments); if (reflectedType == Service) { - var loggers = []; + var allLoggers = []; if (positionalArguments[2] is List) { for (var item in positionalArguments[2] as List) { if (item is Logger) { - loggers.add(item); + allLoggers.add(item); } } } return MockReflectedInstance(Service( positionalArguments[0] as Logger, positionalArguments[1] as Logger, - loggers, + allLoggers, )); } if (reflectedType == ConsoleLogger) { @@ -286,12 +296,22 @@ class MockReflectedClass extends ReflectedType implements ReflectedClass { @override bool isAssignableTo(ReflectedType? other) { + // Handle primitive types and exact matches + if (reflectedType == other?.reflectedType) { + return true; + } + // Handle Logger implementations if (reflectedType == ConsoleLogger && other?.reflectedType == Logger) { return true; } if (reflectedType == FileLogger && other?.reflectedType == Logger) { return true; } + // Handle List + if (reflectedType.toString() == 'List' && + other?.reflectedType.toString() == 'List') { + return true; + } return false; } } @@ -364,6 +384,18 @@ class MockReflectedType implements ReflectedType { if (reflectedType == other?.reflectedType) { return true; } + // Handle Logger implementations + if (reflectedType == ConsoleLogger && other?.reflectedType == Logger) { + return true; + } + if (reflectedType == FileLogger && other?.reflectedType == Logger) { + return true; + } + // Handle List + if (reflectedType.toString() == 'List' && + other?.reflectedType.toString() == 'List') { + return true; + } return false; } @@ -405,13 +437,20 @@ void main() { // Reset instance count SingletonService.instanceCount = 0; - // Register implementations + // Register implementations with attributes container.registerAttributeBindings(ConsoleLogger); container.registerAttributeBindings(FileLogger); container.registerAttributeBindings(SingletonService); // Set ConsoleLogger as default implementation for Logger container.bind(Logger).to(ConsoleLogger); + + // Register FileLogger for @Inject + container.registerSingleton(FileLogger(filename: 'app.log')); + + // Register implementations for @InjectAll + container.registerFactory>((c) => + [container.make(), container.make()]); }); test('can bind implementation using @Injectable', () {