我能否以某种方式传递类型信息以简化此操作?

时间:2017-03-31 03:16:43

标签: json jackson kotlin

我有很多像这样的代码,除PositionJson类型外,它们都是相同的,可以是AnotherJsonFooJsonBarJson

有没有什么方法可以将所有这些代码扩展到一个函数中,我可以以某种方式将其传递给它类型?所以我没有几个几乎完全相同的代码乱丢我的班级?

我不确定这是否可能,只是想我会问,因为这样做会很好......

    /**
     * @return the _open_ [PositionJson]s
     */
    val positions: Array<PositionJson>?
        @Throws(AccountsAPIException::class)
        get() {
            val service = constructServiceURL(POSITIONS, null, true)
            try {
                val messageJson = mapper.readValue<MessageJson<Array<PositionJson>>>(
                        callURL(service),
                        object: TypeReference<MessageJson<Array<PositionJson>>>() {

                        })

                val error = messageJson.error
                if (error != null) throw AccountsAPIException(error.errorCode, error.description)
                return messageJson.data
            } catch (e: Exception) {
                throw AccountsAPIException(e)
            }
        }

1 个答案:

答案 0 :(得分:2)

你可以用泛型做你想做的事。但是,要使用泛型,我们首先需要将这个巨大的代码块提取到一个方法中:

val positions: Array<PositionJson>? get() = getPositions()

fun getPositions(): Array<PositionJson>? {
    ...
}

我们还没有解决问题,但现在我们能够通过使getPositions通用来解决它(注意我也重命名了这个函数):

val positions: Array<PositionJson> get() = getArrayOf<PositionJson>()
// thanks to type inference I can omit the type on getArrayOf if desired:
val positions: Array<PositionJson> get() = getArrayOf()

fun <T> getArrayOf(): Array<T>? {
    val service = constructServiceURL(POSITIONS, null, true)
    try {
        val messageJson = mapper.readValue<MessageJson<Array<T>>>(
                callURL(service),
                object: TypeReference<MessageJson<Array<T>>>() {

                })

        val error = messageJson.error
        if (error != null) throw AccountsAPIException(error.errorCode, error.description)
        return messageJson.data
    } catch (e: Exception) {
        throw AccountsAPIException(e)
    }
}

完美!由于类型擦除,这将无法编译。但我们也可以通过创建函数inline并创建类型参数reified来解决这个问题:

inline fun <reified T: Any> getArrayOf(): Array<T>? {
    ...
}

那应该这样做。现在您可以根据需要重用此功能:

val positions: Array<PositionJson>? get() = getArrayOf()
val persons: Array<PersonJson>? get() = getArrayOf()
val bananas: Array<BananaJson>? get() = getArrayOf()

inline fun <reified T: Any> getArrayOf(): Array<T>? {
    val service = constructServiceURL(POSITIONS, null, true)
    try {
        val messageJson = mapper.readValue<MessageJson<Array<T>>>(
                callURL(service),
                object: TypeReference<MessageJson<Array<T>>>() {

                })

        val error = messageJson.error
        if (error != null) throw AccountsAPIException(error.errorCode, error.description)
        return messageJson.data
    } catch (e: Exception) {
        throw AccountsAPIException(e)
    }
}

最后一件事:请注意,在我的所有示例中,我使用了属性getter(get() = ...),就像在原始代码中一样。但是,我强烈怀疑你不想使用吸气剂。每次有人访问您的财产时都会调用Getter,在这种情况下,每次有人读取您将要调用的positions属性constructServiceURL并拨打服务电话等时都会调用。如果您需要代码只发生一次然后您应该只调用getArrayOf()一次并将结果分配给您的属性:

val positions: Array<PositionJson>? = getArrayOf()
// this syntax would also work:
val positions = getArrayOf<PositionJson>()