From 8b9c8d2774e8d559d8e6a5aa663e7a37b29e2ec2 Mon Sep 17 00:00:00 2001 From: Mike Bierlee Date: Thu, 27 Nov 2014 00:33:13 +0100 Subject: [PATCH] Add ability to resolve type which has multiple registrations by qualifier --- source/poodinis/dependency.d | 45 ++++++++++++++++++++++++---------- source/poodinis/registration.d | 11 +++++++++ test/poodinis/dependencytest.d | 28 ++++++++++++++++++++- 3 files changed, 70 insertions(+), 14 deletions(-) diff --git a/source/poodinis/dependency.d b/source/poodinis/dependency.d index 3675fb1..7c19c16 100644 --- a/source/poodinis/dependency.d +++ b/source/poodinis/dependency.d @@ -53,9 +53,12 @@ class DependencyContainer { writeln(format("DEBUG: Register type %s (as %s)", concreteType.toString(), registeredType.toString())); } - auto existingRegistration = getRegistration(registeredType, concreteType); - if (existingRegistration) { - return existingRegistration; + auto existingCandidates = registeredType in registrations; + if (existingCandidates) { + auto existingRegistration = getRegistration(*existingCandidates, concreteType); + if (existingRegistration) { + return existingRegistration; + } } Registration newRegistration = new Registration(registeredType, concreteType); @@ -64,13 +67,11 @@ class DependencyContainer { return newRegistration; } - private Registration getRegistration(TypeInfo registeredType, TypeInfo_Class concreteType) { - auto existingCandidates = registeredType in registrations; - if (existingCandidates) { - foreach(existingRegistration ; *existingCandidates) { - if (existingRegistration.instantiatableType == concreteType) { - return existingRegistration; - } + private Registration getRegistration(Registration[] candidates, TypeInfo concreteType) { + foreach(existingRegistration ; candidates) { + writeln("DEBUG: Test type " ~ existingRegistration.instantiatableType.toString() ~ " with " ~ concreteType.toString()); + if (existingRegistration.instantiatableType == concreteType) { + return existingRegistration; } } @@ -78,9 +79,15 @@ class DependencyContainer { } public RegistrationType resolve(RegistrationType)() { + return resolve!(RegistrationType, RegistrationType)(); + } + + public RegistrationType resolve(RegistrationType, QualifierType : RegistrationType)() { TypeInfo resolveType = typeid(RegistrationType); + TypeInfo qualifierType = typeid(QualifierType); + debug { - writeln("DEBUG: Resolving type " ~ resolveType.toString()); + writeln("DEBUG: Resolving type " ~ resolveType.toString() ~ " with qualifier " ~ qualifierType.toString()); } auto candidates = resolveType in registrations; @@ -88,8 +95,7 @@ class DependencyContainer { throw new ResolveException("Type not registered.", resolveType); } - auto registration = (*candidates)[0]; - + Registration registration = getQualifiedRegistration(resolveType, qualifierType, *candidates); RegistrationType instance = cast(RegistrationType) registration.getInstance(); if (!autowireStack.canFind(registration)) { @@ -101,6 +107,19 @@ class DependencyContainer { return instance; } + private Registration getQualifiedRegistration(TypeInfo resolveType, TypeInfo qualifierType, Registration[] candidates) { + if (resolveType == qualifierType) { + if (candidates.length > 1) { + string candidateList = candidates.toConcreteTypeListString(); + throw new ResolveException("Multiple qualified candidates available: " ~ candidateList ~ ". Please specify qualifier.", resolveType); + } + + return candidates[0]; + } + + return getRegistration(candidates, qualifierType); + } + public void clearAllRegistrations() { registrations.destroy(); } diff --git a/source/poodinis/registration.d b/source/poodinis/registration.d index 24f4658..68916f1 100644 --- a/source/poodinis/registration.d +++ b/source/poodinis/registration.d @@ -119,3 +119,14 @@ public Registration existingInstance(Registration registration, Object instance) registration.registationScope = new ExistingInstanceScope(instance); return registration; } + +public string toConcreteTypeListString(Registration[] registrations) { + auto concreteTypeListString = ""; + foreach (registration ; registrations) { + if (!concreteTypeListString.length) { + concreteTypeListString ~= ", "; + } + concreteTypeListString ~= registration.instantiatableType.toString(); + } + return concreteTypeListString; +} diff --git a/test/poodinis/dependencytest.d b/test/poodinis/dependencytest.d index 8e43a58..7eaa5e2 100644 --- a/test/poodinis/dependencytest.d +++ b/test/poodinis/dependencytest.d @@ -172,7 +172,7 @@ version(unittest) { auto autowiredInstance = container.resolve!AutowiredClass; assert(componentInstance.autowiredClass is autowiredInstance, "Member is not autowired upon resolving"); } - + // Test circular autowiring unittest { auto container = new DependencyContainer(); @@ -290,4 +290,30 @@ version(unittest) { assert(firstRegistration is secondRegistration, "First registration is not the same as the second of equal types"); } + + // Test resolve registration with multiple qualifiers + unittest { + auto container = new DependencyContainer(); + container.register!(Color, Blue); + container.register!(Color, Red); + try { + container.resolve!Color; + } catch (ResolveException e) { + return; + } + assert(false); + } + + // Test resolve registration with multiple qualifiers using a qualifier + unittest { + auto container = new DependencyContainer(); + container.register!(Color, Blue); + container.register!(Color, Red); + auto blueInstance = container.resolve!(Color, Blue); + auto redInstance = container.resolve!(Color, Red); + + assert(blueInstance !is redInstance, "Resolving type with multiple, different registrations yielded the same instance"); + assert(blueInstance !is null, "Resolved blue instance to null"); + assert(redInstance !is null, "Resolved red instance to null"); + } } \ No newline at end of file