Releases: evant/kotlin-inject
0.7.2
[0.7.2] 2024-09-13
Changed
- kotlin updated to 2.0.0
Fixed
- Fixed various issues with qualifier annotations.
- Fixed issue with inner class or companion inside a component extending the component interface causing an error.
- Fixed crash when attempting to display a type parameter.
- Added ksp work-around when running multiple rounds to prevent a FileAlreadyExistsException on a duplicate symbol.
- Fixed injecting into a java constructor that doesn't have a nullability annotation defined.
- Fixed various issues when resolving cycles.
0.7.1
0.7.0
[0.7.0] 2024-06-12
Changed
@Scope
annotations now take arguments into account. This means for example, if you havethen the scope:@Scope annotation class NamedScope(val value: String)
@NamedScope("one")
and@NamedScope("two")
would be treated as distinct. Previously they were
treated as the same scope.- Legacy implicit assisted injection (not using the
@Assisted
annotation) is now an error. - The build will now fail if multiple qualifiers are applied in the same place, instead of picking the first one. This
applies both to the new annotation (see below) andjavax.inject.Qualifier
. A minor exception is you are allowed to
have one of each type to aid in migration. In that case theme.tatarka.inject
one will be chosen.
Added
- Added a
me.tatarka.inject.annotations.Qualifier
annotation as an alternative to using typealias. For example, you
could do:This behaves the same as@Qualifier annotation class Named(val value: String) @Inject class MyClass(@Named("one") val one: String, @Named("two") val two: String) @Component abstract class MyComponent { abstract val myClass: MyClass @Provides @Named("one") fun provideOne(): String = "one" @Provides @Named("two") fun provideTwo(): String = "two" }
javax.inject.Qualifier
does when you haveme.tatarka.inject.enableJavaxAnnotations=true
. - Added a new
@KmpComponentCreate
annotation for nicer multiplatform support. This allows you to create component
instances from common code when generating platform-specific outputs.see the new multiplatform docs for more details.// src/commonMain @Component abstract class MyKmpComponent @KmpComponentCreate expect fun createKmp(): MyKmpComponent
- You can now use an
@Inject
annotation on an inner class provided the outer class can be provided.@Inject class Outer { @Inject inner class Inner } @Component abstract class MyComponent { abstract val inner: Outer.Inner }
Removed
- The KAPT backend is removed, please migrate to KSP if you haven't already.
Fixed
- Fixed cases of invalid code generation (#321, #337, #313).
- Fixed an exception thrown on KSP2 when running multiple rounds (google/ksp#1854).
- Fixed various issues with handling method overrides in components (#309, #375)
- Allow scope annotations on both an interface and component implementation if they are the same scope (#320).
v0.6.3
v0.6.2
[0.6.2] 2023-08-28
Changed
- Updated kotlin to 1.9.0
- If a dependency's scope is not found on the component providing it, a better error message is given.
- Adding a
@Provides
annotation on an abstractfun
orval
will now warn that it has no effect. - When overriding a method the parent is checked to see if it has a
@Provides
annotation. This makes the example in
the README actually work:@NetworkScope abstract class NetworkComponent { @NetworkScope @Provides abstract fun api(): Api } @Component abstract class RealNetworkComponent : NetworkComponent() { // This is now treated as a @Provides even if not annotated directly override fun api(): Api = RealApi() }
Fixed
-
Typealiases are treated as separate types in multibinding. This is consistent with other
uses of typealiases.For example:
typealias MyString = String @Component abstract class MyComponent { abstract val stringItems: Set<String> abstract val myStringItems: Set<MyString> @Provides @IntoSet fun stringValue1(): String = "string" @Provides @IntoSet fun stringValue2(): MyString = "myString" }
stringItems
will contain{"string"}
andmyStringItems
will contain{"myString"}
. -
Lambda types now work in set multibindings.
@Component abstract class MyComponent { abstract val lambdaSet: Set<() -> String> @Provides @IntoSet fun lambda1(): () -> String = { "one" } @Provides @IntoSet fun lambda2(): () -> String = { "two" } }
-
Assisted injection no longer works with scopes or cycles. These two cases would over-cache the instance, ignoring the
assisted arguments. They now throw an error instead.// now throws cycle error when providing @Inject class AssistedCycle(val factory: (Int) -> AssistedCycle, @Assisted val arg: Int) // now throws error when providing @MyScope @Inject class AssistedScoped(@Assisted val arg: Int)
-
Fixed edge case where accessing a parent scoped dependency from a lazy cycle generated invalid code.
v0.6.1
v0.6.0
[0.6.0] 2202-12-21
Changed
-
Added the ability to explicitly mark assisted injection parameters with an
@Assisted
annotation. Not providing them
will currently warn which will become an error in the future. This allows better documentation on which params are
injected and which ones are provided by the caller. It also allows more flexibility for parameter ordering, you can
put the assisted params at the start instead of at the end if you so choose.For example, if you have:
@Inject class AssistedClass(arg1: One , arg2: Two, arg3: Three) @Inject Usage(createAssistedClass: (Two, Three) -> AssistedClass)
you should update it to:
@Inject class AssistedClass(arg1: One , @Assisted arg2: Two, @Assisted arg3: Three)
Fixed
@Inject
annotations being ignored if used through a typealias, ex:typealias MyInject = Inject @MyInject class MyClassToInject
v0.5.1
v0.5.0
[0.5.0] 2022-07-02
Changed
-
The kapt backend is now deprecated and will be removed in a future release. Please migrate to ksp instead.
-
Introduced some stricter checks to catch issues with certain graph setups. This may cause graphs that compiled before
to no longer compile. Specifically:@MyScope @Component abstract class ParentComponent @MyScope @Component abstract class ChildComponent(@Component val parent: ParentComponent)
will fail with:
Cannot apply scope: @MyScope ChildComponent as scope @MyScope is already applied to parent ParentComponent
as it's ambiguous what the lifetime of the given scope should be. And:
@Component abstract class ParentComponent { @Provides fun foo(bar: Bar): Foo = ... } @Component abstract class ChildComponent(@Component val parent: ParentComponent) { abstract val foo: Foo @Provides fun bar(): Bar = ... }
will fail with:
Cannot find an @Inject constructor or provider for: Bar
In other words a parent component can no longer depend on a dependency provided by a child component. Not only does
this lead to confusing graphs, but it can lead to memory leaks if the parent component lives longer than the child and
ends holding on to that child dependency.
Added
- You can now use function and
Lazy
types inSet
. This allows you to lazily construct its entries without having to
change the type on your@IntoSet
methods.@Component abstract class MyComponent { val funSet: Set<() -> Foo> val lazySet: Set<Lazy<Foo>> @Provides @IntoSet fun foo1(): Foo = ... @Provides @IntoSet fun foo2(): Foo = ... }
Fixed
- Fixed issue with name collisions when generating arguments. This could cause invalid code to be generated as the inner
arg would shadow the outer arg that was attempted to be used. - Improved the error message for scoped provides in unscoped component.
- Fixed printing of an inner type to include the outer class. i.e. You will now get
Parent.Child
in error messages
instead of justChild
which can make it easier to find the location of the error.
v0.4.1
[0.4.1] 2022-01-01
Changed
- Improved generated code formatting.
- Removed explicit retention annotation to get rid of kotlin js warnings.
Fixed
- Fixes conflicting declarations when scoped
@Provides
functions returned the same type with different generic args. - Fixes default parameter handling with lambda or lazy values.
- Fixes to kotlin native implementation that should make it more usable across threads.
Note: the new memory model limitation is still present, but you can use https://github.com/touchlab/Stately to wrap
the access when using the legacy memory model.