Skip to main content

Component (Experimental)

Experimental

The Component feature is experimental. API may change in the future.

What is the Component

The Component allows you to group provided types and organize dependencies.

By default, provided types are registered on the root component. However, you can specify another component when providing types.

// Registered in RootComponent
@Provides
class NormalClass

// Registered in SomeComponent
@SomeComponent
@Provides
class ComponentClass

Types registered in a component can only refer to types within the same component and types of the root component.

@Provides
class NormalClass

@SomeComponent
@Provides
class SameComponentClass

@OtherComponent
@Provides
class OtherComponentClass

@SomeComponent
@Provides
class ComponentClass(
val normalClass: NormalClass, // can be injected
val sameComponentClass: SameComponentClass, // can be injected
val otherComponentClass: OtherComponentClass, // cannot be injected!
)

You can provide extra dependencies for your components during field injection. This can be used to provide instances created by the platform or dynamically change the dependencies.

class ExtraClass // not provided

@SomeComponent
@Provides
class ComponentClass(
val extraClass: ExtraClass,
)
@OptIn(ExperimentalKojectApi::class)
val componentClass = inject<ComponentClass>(
componentExtras = SomeComponentExtras(ExtraClass())
)

Limitation

Koject does not offer a component hierarchy to avoid complexity.

Create a custom Component

tip

In most cases, a custom component is not needed. Adding components can add complexity. Carefully consider your need to add it.

To create a custom component, first, create a component annotation using the @Component annotation.

@OptIn(ExperimentalKojectApi::class)
@Component
annotation class CustomComponent

Next, add the component annotation created when providing and register the type to the component.

@Provides
@CustomComponent
class SomeClass(
val extraClass: ExtraClass
)

Then, create an Extras class using the ComponentExtras interface. At that time, specify the component to be created.

If the component requires additional dependencies, provide them in the properties of the Extras class.

@ExperimentalKojectApi
class CustomComponentExtras(
val extraClass: ExtraClass // provide ExtraClass
): ComponentExtras<CustomComponent> // for CustomComponent

Otherwise, create a class with no properties.

@ExperimentalKojectApi
class EmptyComponentExtras: ComponentExtras<EmptyComponent>

Finally, call the inject() function with the componentExtras parameter to get the type of the component.

@OptIn(ExperimentalKojectApi::class)
val someClass = inject<SomeClass>(
componentExtras = CustomComponentExtras(ExtraClass())
)
MIGRATION (VERSION 1.2.0)

The ComponentExtras API has changed since v1.2.0.

// Until v1.1.0
@ExperimentalKojectApi
@ComponentExtras(CustomComponent::class)
class CustomComponentExtras(
val extra: ExtraClass
)

// Since v1.2.0
@ExperimentalKojectApi
class CustomComponentExtras(
val extra: ExtraClass
): ComponentExtras<CustomComponent>

Advanced usage

In ComponentExtras, all non-private properties are treated as provides, and getters are also available.

class SomeComponentExtras(
// provide SomeClass1
val someClass1: SomeClass1
): ComponentExtras<SomeComponent> {
// provide SomeClass2
val someClass2: SomeClass2 = SomeClass2()

// provide SomeClass3
val someClass3: SomeClass3
get() = SomeClass3()
}

@Qualifier and @Named annotations can be used to distinguish between multiple providers of the same type.

class SomeComponentExtras: ComponentExtras<SomeComponent> {
// provide with a qualifier
@SomeQualifier
val someClass2: SomeClass2 = SomeClass2()

// provide with a name
@Named("some-name")
val someClass3: SomeClass3
get() = SomeClass3()
}

Note that @Singleton is not available in ComponentExtras.