Skip to content

Commit

Permalink
Changed circular dependency exception strategy (see #161)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexgarbarev committed Feb 3, 2014
1 parent e7daa0b commit aca04e1
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ - (void)configureInvocation:(NSInvocation*)invocation withFactory:(TyphoonCompon
if (parameter.type == TyphoonParameterInjectionTypeReference)
{
TyphoonParameterInjectedByReference* byReference = (TyphoonParameterInjectedByReference*) parameter;
[[factory stack] peekForKey:byReference.reference]; //Raises circular dependencies exception if already initializing.
[[factory stack] peekInstanceForKey:byReference.reference]; //Raises circular dependencies exception if already initializing.
id reference = [factory componentForKey:byReference.reference];
[invocation setArgument:&reference atIndex:parameter.index + 2];
}
Expand Down
8 changes: 5 additions & 3 deletions Source/Factory/Internal/TyphoonCallStack.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@

- (TyphoonStackElement*)pop;

/**
* Peeks for the given key. If the key represents an instance undergoing initializer injection, raises a circular init exception.
*/
- (TyphoonStackElement*)peekForKey:(NSString*)key;

/**
* Peeks instance for the given key. If the key represents an instance undergoing initializer injection, raises a circular init exception.
*/
- (id)peekInstanceForKey:(NSString *)key;

- (BOOL)isResolvingKey:(NSString*)key;

- (BOOL)isEmpty;
Expand Down
19 changes: 13 additions & 6 deletions Source/Factory/Internal/TyphoonCallStack.m
Original file line number Diff line number Diff line change
Expand Up @@ -72,18 +72,25 @@ - (TyphoonStackElement*)peekForKey:(NSString*)key
{
if ([item.key isEqualToString:key])
{
if ([item isInitializingInstance])
{
[NSException raise:@"CircularInitializerDependence"
format:@"The object for key %@ is currently initializing, but was specified as init dependency in another object",
item.key];
}
return item;
}
}
return nil;
}

- (id)peekInstanceForKey:(NSString*)key
{
TyphoonStackElement* stackElement = [self peekForKey:key];

if ([stackElement isInitializingInstance]) {
[NSException raise:@"CircularInitializerDependence"
format:@"The object for key %@ is currently initializing, but was specified as init dependency in another object",
stackElement.key];
}

return stackElement.instance;
}


- (BOOL)isEmpty
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,10 @@ - (void)injectAssemblyOnInstance:(id <TyphoonComponentFactoryAware>)instance

- (id)buildSharedInstanceForDefinition:(TyphoonDefinition*)definition
{
TyphoonStackElement* stackElement = [_stack peekForKey:definition.key];
if (stackElement)
id instance = [_stack peekInstanceForKey:definition.key];
if (instance)
{
return stackElement.instance;
return instance;
}
return [self buildInstanceWithDefinition:definition];
}
Expand Down
28 changes: 8 additions & 20 deletions Tests/Factory/Shared/TyphoonSharedComponentFactoryTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -260,27 +260,15 @@ - (void)test_resolves_chains_of_circular_dependencies_of_singletons_injected_by_
assertThat(notSingletonA.dependencyOnA, is(singletonA));
}

- (void)test_initializer_injected_component_raises_exception_for_circular_dependency
- (void)test_initializer_injected_component_is_correctly_resolved_in_circular_dependency
{
@try
{
PrototypeInitInjected* initializerInjected = [_circularDependenciesFactory componentForType:[PrototypeInitInjected class]];
STFail(@"Should've raised exception");
}
@catch (NSException* e)
{
assertThat([e description], equalTo(
@"The object for key prototypeInitInjected is currently initializing, but was specified as init dependency in another object"));
}

//FIXME: Old test: We were leaning towards supporting circular deps in initializers. . decision?
// PrototypeInitInjected* initializerInjected = [_circularDependenciesFactory componentForType:[PrototypeInitInjected class]];
// PrototypePropertyInjected* propertyInjected = [_circularDependenciesFactory componentForType:[PrototypePropertyInjected class]];
// // should be expected class, but not same instance
// assertThat(initializerInjected.prototypePropertyInjected, instanceOf([PrototypePropertyInjected class]));
// assertThat(initializerInjected.prototypePropertyInjected, isNot(propertyInjected));
// assertThat(propertyInjected.prototypeInitInjected, instanceOf([PrototypeInitInjected class]));
// assertThat(propertyInjected.prototypeInitInjected, isNot(initializerInjected));
PrototypeInitInjected* initializerInjected = [_circularDependenciesFactory componentForType:[PrototypeInitInjected class]];
PrototypePropertyInjected* propertyInjected = [_circularDependenciesFactory componentForType:[PrototypePropertyInjected class]];
// should be expected class, but not same instance
assertThat(initializerInjected.prototypePropertyInjected, instanceOf([PrototypePropertyInjected class]));
assertThat(initializerInjected.prototypePropertyInjected, isNot(propertyInjected));
assertThat(propertyInjected.prototypeInitInjected, instanceOf([PrototypeInitInjected class]));
assertThat(propertyInjected.prototypeInitInjected, isNot(initializerInjected));
}

/* ====================================================================================================================================== */
Expand Down

0 comments on commit aca04e1

Please sign in to comment.