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:
FirstActivitywants to startSecondActivityand passFooandBaras input;SecondActivityusesSecondViewModel;SecondViewModelexpectFooandBarto 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:
apimodule where a single service (interface) lives;implmodule where the service implementation is defined, and annotated withAutoBinds;appmodule where DI starts and service is requested.
Moreover:
- the
annotationsmodule define other services to show the usage ofAutoBinds.annotationsparameter; - inside the
annotationsmodule theAutoUninstallannotation is used in the test source set to replace the implementations with fakes without referencing the generated modules; - inside
multiroundmodule you can find a sample usage ofAutoProvidesannotation.
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