Last active
August 24, 2021 13:27
-
-
Save bfreuden/a866b21c5a6342a3ce1ed26aa636f9f6 to your computer and use it in GitHub Desktop.
Toothpick question
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package bfreuden | |
| import toothpick.InjectConstructor | |
| import toothpick.ProvidesSingleton | |
| import toothpick.ktp.KTP | |
| import toothpick.ktp.binding.bind | |
| import toothpick.ktp.binding.module | |
| import javax.inject.Named | |
| import javax.inject.Provider | |
| import javax.inject.Scope | |
| import javax.inject.Singleton | |
| /* | |
| The app has many shard (2 in this example) having the same object structure. | |
| All objects inside shards are singletons: | |
| - unique database client for all DAOs | |
| - unique FooDAO (injected into the PowerDAO) | |
| ! denotes singletons of the shard1 scope. | |
| ? denotes singletons of the shard2 scope. | |
| app (scope) | |
| / \ | |
| ----------- ------------ | |
| / \ | |
| shard1 (scope) shard2 (scope) | |
| / \ / \ | |
| !PowerDAO !FooDAO ?PowerDAO ?FooDAO | |
| / \ \ / \ \ | |
| !FooDAO !DBCLient !DBCLient ?FooDAO ?DBCLient ?DBCLient | |
| | | | |
| !DBCLient ?DBCLient | |
| */ | |
| @Scope | |
| @Retention(AnnotationRetention.RUNTIME) | |
| annotation class ShardSingleton | |
| @ProvidesSingleton | |
| @InjectConstructor | |
| @ShardSingleton | |
| class DBClientProvider(@Named("appConfig")val appConfig: Map<String, String>): Provider<DBClient> { | |
| override fun get() = DBClient(appConfig["dpPort"]!!.toInt()) | |
| } | |
| class DBClient(val port: Int) | |
| @Singleton // the FooDAO is not a singleton without this annotation | |
| @ShardSingleton | |
| @InjectConstructor | |
| class FooDAO(val dbClient: DBClient) | |
| @Singleton | |
| @ShardSingleton | |
| @InjectConstructor | |
| class PowerDAO(val dbClient: DBClient, val fooDAO: FooDAO) | |
| @Singleton | |
| @ShardSingleton | |
| @InjectConstructor | |
| class Shard(@Named("appConfig")val appConfig: Map<String, String>, val fooDAO: FooDAO, val powerDAO: PowerDAO) | |
| @InjectConstructor | |
| class App(@Named("appConfig")val appConfig: Map<String, String>) { | |
| var shard1: Shard = KTP.openScopes("app", "shard1") | |
| .supportScopeAnnotation(ShardSingleton::class.java) | |
| .installModules(module { | |
| // does not work without this explicit binding | |
| bind<DBClient>().toProvider(DBClientProvider::class) | |
| }).getInstance(Shard::class.java) | |
| var shard2: Shard = KTP.openScopes("app", "shard2") | |
| .supportScopeAnnotation(ShardSingleton::class.java) | |
| .installModules(module { | |
| // does not work without this explicit binding | |
| bind<DBClient>().toProvider(DBClientProvider::class) | |
| }).getInstance(Shard::class.java) | |
| } | |
| fun main() { | |
| val app = KTP.openScope("app") | |
| .installModules( | |
| module { | |
| bind<Map<String, String>>().withName("appConfig").toInstance(mapOf("dpPort" to "12")) | |
| } | |
| ) | |
| .getInstance(App::class.java) | |
| val shard1 = app.shard1 | |
| println("shard1 $shard1") | |
| println("shard1.appConfig ${shard1.appConfig}") | |
| println("shard1.fooDAO ${shard1.fooDAO} (${shard1.fooDAO.dbClient})") | |
| println("shard1.powerDAO ${shard1.powerDAO} (${shard1.powerDAO.fooDAO})") | |
| println("shard1.powerDAO.dbClient ${shard1.powerDAO.dbClient}") | |
| println("shard1.powerDAO.fooDAO ${shard1.powerDAO.fooDAO} (${shard1.powerDAO.fooDAO.dbClient})") | |
| println() | |
| val shard2 = app.shard2 | |
| println("shard2 $shard2") | |
| println("shard2.appConfig ${shard2.appConfig}") | |
| println("shard2.fooDAO ${shard2.fooDAO} (${shard2.fooDAO.dbClient})") | |
| println("shard2.powerDAO ${shard2.powerDAO} (${shard2.powerDAO.fooDAO})") | |
| println("shard2.powerDAO.dbClient ${shard2.powerDAO.dbClient}") | |
| println("shard2.powerDAO.fooDAO ${shard2.powerDAO.fooDAO} (${shard2.powerDAO.fooDAO.dbClient})") | |
| } | |
| /* | |
| ------------------- | |
| Program output: | |
| => FooDAO and DBClient are shard singletons | |
| shard1 bfreuden.Shard@6b57696f | |
| shard1.appConfig {dpPort=12} | |
| shard1.fooDAO bfreuden.FooDAO@38bc8ab5 (bfreuden.DBClient@687080dc) | |
| shard1.powerDAO bfreuden.PowerDAO@23d2a7e8 (bfreuden.FooDAO@7a9273a8) | |
| shard1.powerDAO.dbClient bfreuden.DBClient@687080dc | |
| shard1.powerDAO.fooDAO bfreuden.FooDAO@7a9273a8 (bfreuden.DBClient@687080dc) | |
| shard2 bfreuden.Shard@26a7b76d | |
| shard2.appConfig {dpPort=12} | |
| shard2.fooDAO bfreuden.FooDAO@4abdb505 (bfreuden.DBClient@7ce6a65d) | |
| shard2.powerDAO bfreuden.PowerDAO@1500955a (bfreuden.FooDAO@e874448) | |
| shard2.powerDAO.dbClient bfreuden.DBClient@7ce6a65d | |
| shard2.powerDAO.fooDAO bfreuden.FooDAO@e874448 (bfreuden.DBClient@7ce6a65d) | |
| ------------------- | |
| Program output without @Singleton annotation on FooDAO: | |
| => DBClient is a shard singleton | |
| => FooDAO is not a shard singleton (PowerDAO has its own instance) | |
| shard1 bfreuden.Shard@6b57696f | |
| shard1.appConfig {dpPort=12} | |
| shard1.fooDAO bfreuden.FooDAO@38bc8ab5 (bfreuden.DBClient@687080dc) | |
| shard1.powerDAO bfreuden.PowerDAO@23d2a7e8 (bfreuden.FooDAO@7a9273a8) | |
| shard1.powerDAO.dbClient bfreuden.DBClient@687080dc | |
| shard1.powerDAO.fooDAO bfreuden.FooDAO@7a9273a8 (bfreuden.DBClient@687080dc) | |
| shard2 bfreuden.Shard@26a7b76d | |
| shard2.appConfig {dpPort=12} | |
| shard2.fooDAO bfreuden.FooDAO@4abdb505 (bfreuden.DBClient@7ce6a65d) | |
| shard2.powerDAO bfreuden.PowerDAO@1500955a (bfreuden.FooDAO@e874448) | |
| shard2.powerDAO.dbClient bfreuden.DBClient@7ce6a65d | |
| shard2.powerDAO.fooDAO bfreuden.FooDAO@e874448 (bfreuden.DBClient@7ce6a65d) | |
| ------------------- | |
| Program output without bind<DBClient>().toProvider(DBClientProvider::class): | |
| Exception in thread "main" toothpick.locators.NoFactoryFoundException: | |
| No factory could be found for class bfreuden.DBClient. | |
| Check that the class has either a @Inject annotated constructor or contains @Inject annotated members. | |
| */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment