Skip to content

Scope Resolution

Stéphane Nicolas edited this page May 8, 2016 · 17 revisions

Scope resolution

Scope resolution is one of the most important part of ToothPick. It's intuitive in some extent.

The core idea is that scopes are always bubbled up when resolving an injection, and looking up for a binding. Toothpick never goes down the scope tree.

At runtime, when ToothPick will create the injection graph to create an instance of a class and its dependencies, Toothpick will crash if a dependency of this class can't be found in the scope itself or its parent scopes.

Here is an example :

//Example of scopes during the life of an Android application

+----------------------------------------------------------------------------------+  Resolution
| +---------------------------------------------------------------+                |  space
| |  application scope = @Singleton :                             | Resolution     |  for Activity
| |        /                    - Scope --> (application)         | space          |  scope
| |       /                     - IDisplay --> DisplayImpl1       | for @Singleton |
| |      /                      - FooSingleton --> (FooSingleton) | scope          |  
| +-----/---------------------------------------------------------+                |
|   activity scope = @ActivitySingleton :                                          |
|                               - Scope --> (activity)                             |
|                               - IDisplay --> DisplayImpl2                        |
|                               - FooActivitySingleton --> (FooActivitySingleton)  |
+----------------------------------------------------------------------------------+

Let's define :

class DisplayImpl1 {@Inject Scope scope}
class DisplayImpl2 {@Inject Scope scope}
@Singleton class FooSingleton {@Inject IDisplay display; @Inject Scope scope}
@ActivitySingleton class FooActivitySingleton {@Inject Scope s; @Inject IDisplay display;}
@Singleton class FooSingletonError {@Inject FooActivitySingleton foo;}

Below, we detail the result of the statement

 scope.getInstance(obj);  

where both obj and scope vary.

scope = application Scope All dependencies will be resolved in the @Singleton resolution space.

  • obj = scope.getInstance(Scope.class)

  • obj = application scope.

  • obj = scope.getInstance(IDisplay.class)

  • obj is an instance of Display1Impl

  • obj.scope = application scope

  • obj is not a singleton, an extra call to getInstance would produce a new instance of DisplayImpl1

  • obj = scope.getInstance(FooSingleton.class)

  • obj is an instance of FooSingleton

  • obj is a singleton, an extra call to getInstance would return the same instance of FooSingleton in this scope and any child scope

  • obj.scope = application scope

  • obj.display is an instance of Display1Impl

  • obj.display.scope = application scope

  • obj = scope.getInstance(FooActivitySingleton.class)

  • would crash as FooActivitySingleton is annotated with @ActivitySingleton and the application scope (or its parents) do not support this annotation.

  • obj = scope.getInstance(FooSingletonError.class)

  • would crash as FooActivitySingleton is annotated with @ActivitySingleton and the application scope (or its parents) do not support this annotation.

scope = activity Scope All dependencies will be resolved in the activity scope resolution space.

  • obj = scope.getInstance(Scope.class)

  • obj = activity scope.

  • obj = scope.getInstance(IDisplay.class)

  • obj is an instance of Display2Impl

  • obj.scope = activity scope

  • obj is not a singleton, an extra call to getInstance would produce a new instance of DisplayImpl2

  • obj = scope.getInstance(FooSingleton.class)

  • obj is the same singleton instance produced by applicationScope.getInstance(FooSingleton.class)

  • obj.scope = application scope

  • obj.display is an instance of Display1Impl

  • obj.display.scope = application scope

  • obj = scope.getInstance(FooActivitySingleton.class)

  • obj is an instance of FooActivitySingleton

  • obj is a singleton, the same instance of FooActivitySingleton would be returned with an extra call of getInstance, in this scope and any child scope

  • obj.scope = activity scope

  • obj.display is an instance of Display2Impl

  • obj.display.scope = activity scope

  • obj = scope.getInstance(FooSingletonError.class)

  • would crash as FooActivitySingleton is annotated with @ActivitySingleton and the application scope (or its parents) do not support this annotation. Though we are in the activity scope, FooSingletonError is annotated with @Singleton and will be created in the application scope.