为什么 Dagger @IntoMap 和 @ClassKey 在 Kotlin 中没有任何意义

问题描述 投票:0回答:1

我正在研究如何使用 dagger 创建 Set(s) 并将其注入 Maps,其 kotlin 代码如下所示

首先没有任何意义的是使用 kotlin

@ClassKey(ErikTenHag::class)
,

即使

ClassKey
注释的实现如下:-

@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
@Retention(RUNTIME)
@MapKey
public @interface ClassKey {
  Class<?> value();
}

例如当我尝试设置时使用 java.lang.Class NOT KClass

@ClassKey(ErikTenHag::class.java)
我收到此错误消息

enter image description here

接下来,当我为地图制作注入位置时,如下所示:-

@JvmSuppressWildcards
data class FootballLeague @Inject constructor(val teamMap: Map<@JvmSuppressWildcards KClass<*>, Set<Player>>) {

我遇到编译时错误

[Dagger/MissingBinding] java.util.Map<kotlin.reflect.KClass<?>,java.util.Set<Player>> cannot be provided without an @Provides-annotated method.

当我制作注射部位时

@JvmSuppressWildcards
data class FootballLeague @Inject constructor(val teamMap: Map<@JvmSuppressWildcards Class<*>, Set<Player>>) {

我的代码编译良好并按要求工作。

我期望《匕首 2》应该有意义还是我错过了什么?

我不喜欢在类定义中使用“*”,我宁愿设置一个具体的接口或类,但是当我这样做时我无法让匕首进行编译...

我尝试按如下方式制作注射部位:-

@JvmSuppressWildcards
data class FootballLeague<M: Manager> @Inject constructor(val teamMap: Map<@JvmSuppressWildcards Class<M>, Set<Player>>) {

但是我的代码无法编译并出现错误

error: [Dagger/MissingBinding] java.util.Map<java.lang.Class<Manager>,java.util.Set<Player>> cannot be provided without an @Provides-annotated method.

我必须使用“*”,还是有一种方法可以限制类类型?

@Module
@InstallIn(SingletonComponent::class)
class FootballTeamModule {

    @Provides
    @ElementsIntoSet
    @Named("LiverpoolPlayers")
    fun providesLiverpoolPlayers(mohamedSalah: MohamedSalah, virgilVanDyke: VirgilVanDyke): Set<Player> {
        return HashSet<Player>(listOf(mohamedSalah, virgilVanDyke))
    }

    @Provides
    @ElementsIntoSet
    @Named("ManchesterPlayers")
    fun providesManchesterPlayers(harryMaguire: HarryMaguire, masonMount: MasonMount, casimiro: CarlosCasimiro): Set<Player> {
        return HashSet<Player>(listOf(harryMaguire, masonMount, casimiro))
    }

    @Provides
    @IntoMap
    @ClassKey(JurgenKlopp::class)
    //@StringKey("JurgenKlopp")
    fun providesLiverpool(@Named("LiverpoolPlayers") players: Set<@JvmSuppressWildcards Player>): Set<Player>
    {
        return players
    }

    @Provides
    @IntoMap
    @ClassKey(ErikTenHag::class)
    //@StringKey("ErikTenHag")
    fun providesManchester(@Named("ManchesterPlayers") players: Set<@JvmSuppressWildcards Player>): Set<Player> {
        return players
    }
}

interface Player {
    fun name(): String
    fun wages(): Double
    fun position(): String

}

interface Manager {
    fun name(): String
    fun nationality(): String
}

class MohamedSalah @Inject constructor() : Player {

    override fun name(): String = this::class.java.simpleName

    override fun wages(): Double = 18200000.00

    override fun position(): String = "Forward"

    override fun toString(): String {
        return "${name()} - ${wages()} - ${position()}"
    }
}

class VirgilVanDyke @Inject constructor() : Player {

    override fun name(): String = this::class.java.simpleName

    override fun wages(): Double = 11440000.00

    override fun position(): String = "Defender"

    override fun toString(): String {
        return "${name()} - ${wages()} - ${position()}"
    }
}

class JurgenKlopp @Inject constructor() : Manager {

    override fun name(): String = this::class.java.simpleName
    override fun nationality(): String = "German"
}

class ErikTenHag @Inject constructor() : Manager {

    override fun name(): String = this::class.java.simpleName
    override fun nationality(): String = "Netherlands"
}

class CarlosCasimiro @Inject constructor() : Player {

    override fun name(): String = this::class.java.simpleName

    override fun wages(): Double = 118200000.00

    override fun position(): String = "Midfield"

    override fun toString(): String {
        return "${name()} - ${wages()} - ${position()}"
    }
}

class MasonMount @Inject constructor() : Player {

    override fun name(): String = this::class.java.simpleName

    override fun wages(): Double = 13000000.00

    override fun position(): String = "Midfield"

    override fun toString(): String {
        return "${name()} - ${wages()} - ${position()}"
    }
}

class HarryMaguire @Inject constructor() : Player {

    override fun name(): String = this::class.java.simpleName

    override fun wages(): Double = 1.50

    override fun position(): String = "Defender"

    override fun toString(): String {
        return "${name()} - ${wages()} - ${position()}"
    }

}

@JvmSuppressWildcards
data class FootballLeague @Inject constructor(val teamMap: Map<@JvmSuppressWildcards Class<*>, Set<Player>>) {
    fun getFootballLeagueInstance() {
        teamMap.entries.forEach {
            println("xxooxx ${it.key} to ${it.value}")
        }

    }
}
kotlin dagger-2
1个回答
0
投票

首先,让我们解决问题的

KClass
/
Class
部分。用 Kotlin 编写的注释总是使用
KClass
而不是
Class
,但这只是一个允许独立于 JVM 的语言概念。实际上,在构建 JVM 时,这些
KClass
参数/参数被编译为纯 Java
Class
es
。因此,Dagger 将它们视为
Class
并且对
KClass
一无所知。

现在关于

Class<*>
类型约束。是的,您可以限制
Class<>
内的类型。为此,您需要声明自定义
@MapKey
关键注释
,如下所示:

@dagger.MapKey
annotation class ManagerClassKey(
    val value: KClass<out Manager>
)

然后使用这个新的

ManagerClassKey
代替
ClassKey

© www.soinside.com 2019 - 2024. All rights reserved.