A library that writes an hilt module for a requested interface implementation.
Prerequisite: project using Hilt for dependencies injection.
In a typical use case, you have:
interface MyInterface
---
class MyImplementation @Inject constructor() : MyInterface
and you need to write a simple module only to bind the right implementation:
@Module
@InstallIn(SingletonComponent::class)
interface MyModule {
@Binds
fun binding(impl: MyImplementation): MyInterface
}
With claymore you can avoid to manually write that Module
, by using @AutoBinds
annotation:
@AutoBinds
class MyImplementation: MyInterface
clamyore will automatically generate the necessary module for you.
You can optionally request claymore to install the binding in a specific hilt component, using the component
parameter.
@AutoBinds(component = ActivityComponent::class)
class MyImplementation: MyInterface
If not set, the SingletonComponent
will be used by default.
You can also request claymore to attach any annotation to the binding method, using the annotations
parameter.
@AutoBinds(annotations = [IntoSet::class])
class MyImplementation: MyInterface
// generates a module with a binding function like
@Binds
@IntoSet
fun binding(impl: MyImplementation): MyInterface
When in tests you need to uninstall module generated by AutoBinds
annotation and so replace real implementations with fakes,
you can avoid to reference module generated by claymore using the AutoUninstall
annotation instead.
@AutoUninstall(
implementations = [
MyImplementation::class,
MyOtherImplementation::class,
]
)
@InstallIn(SingletonComponent::class)
@Module
object TestModule {
@Provides
fun fakeImplementation(): MyInterface = FakeImplementation()
@Provides
fun otherFakeImplementation(): MyOtherInterface = OtherFakeImplementation()
}
claymore will generate a module that replaces generated MyImplementationModule
and MyOtherImplementationModule
for you.
Again, you can set the component where replace the modules, otherwise SingletonComponent
is used by default.
AutoProvides
is an experimental annotation that wants to erase all the boilerplate code needed to inject parameter into an Android ViewModel
through SavedStateHandle.
Given the following scenario:
FirstActivity
wants to startSecondActivity
and passFoo
andBar
as input;SecondActivity
usesSecondViewModel
;SecondViewModel
expectFoo
andBar
to be injected as properties.
So we can use AutoProvides
annotation on top of an interface that define an invoke
operator function that take all inputs as parameter and return an Intent
.
Such interface works as a contract between the two activities and the view model, defining what are expected as inputs.
@AutoProvides(activityClass = SecondActivity::class)
interface SecondActivityIntent {
// this can be read as a contract on how to start the SecondActivity
// qualifiers are needed to avoid clash between same input type
@Qualifier
annotation class FirstArg
@Qualifier
annotation class SecondArg
operator fun invoke(
@FirstArg firstArg: String,
@SecondArg secondArg: String,
): Intent
}
@AndroidEntryPoint
class SecondActivity: Activity() {
val viewModel: SecondViewModel by viewModels()
...
}
@HiltViewModel
class SecondViewModel @Inject constructor(
@SecondActivityIntent.FirstArg firstArg: String,
@SecondActivityIntent.SecondArg secondArg: String,
): ViewModel() {
...
}
@AndroiEntryPoint
class FirstActivity: Activity() {
// the injection is provided by claymore itself
@Inject lateinit var secondActivityIntent: SecondActivityIntent
...
fun startSecondActivity() {
startActivity(
secondActivityIntent(
firstArg = "Foo",
secondArg = "Bar",
)
)
}
}
Take a look at the :demo
module for a sample usage.
In this simple project we have:
api
module where a single service (interface) lives;impl
module where the service implementation is defined, and annotated withAutoBinds
;app
module where DI starts and service is requested.
Moreover:
- the
annotations
module define other services to show the usage ofAutoBinds.annotations
parameter; - inside the
annotations
module theAutoUninstall
annotation is used in the test source set to replace the implementations with fakes without referencing the generated modules; - inside
multiround
module you can find a sample usage ofAutoProvides
annotation.
Claymore is available in Maven Central Repository:
repositories {
mavenCentral()
}
dependencies {
compileOnly 'io.github.alecarnevale:claymore-annotations:x.y.z'
}
In order to completely enable claymore
integration you need to apply the ksp plugin
plugins {
id 'com.google.devtools.ksp'
}
dependencies {
ksp 'io.github.alecarnevale:claymore-processors:x.y.z'
}
- KotlinPoet https://github.com/square/kotlinpoet
- Kotlin Compile Testing https://github.com/tschuchortdev/kotlin-compile-testing