如何为多个相似的 API JSON 响应结构的多个数据 class 编写 Kotlin Base class - 已关闭

how to write Kotlin Base class for multiple data class for multiple similar API JSON response structure - CLOSED

所有 API JSON 响应将具有以下结构:

{
    "status": <Integer>
    "data": <Object or List of Objects>
    "message": <String>
}

唯一改变的 属性 是 'data',它可以是任何对象或对象列表。 那么有没有办法创建一个 BaseResponse class like

open class BaseResponse<T> (
    @SerializedName("status")
    val status: Int,
    @SerializedName("data")
    abstract val `data`: T,
    @SerializedName("message")
    val message: String
)

和响应 classes

data class HelloResponse (
    override val `data`: Hello
) : BaseResponse<Hello> {
    data class Hello (
        @SerializedName("hello")
        val hello: String
    )
}


data class HellosResponse (
    override val `data`: List<Hello>
) : BaseResponse<List<Hello>> {
    data class Hello (
        @SerializedName("hello")
        val hello: String
    )
}

我真正想要的是只覆盖data属性,这样我就不必写状态和消息属性 对于我写的每个响应子数据 class。我不想在我的子 class 中写状态和消息并将其传递给基 class,因为我仍然会写这两个属性,所以与创建数据 class 没有区别状态和消息。

所以不能像

data class HelloResponse (
    val status: Int,
    override val `data`: Hello,
    val message: String
) : BasicResponse<Hello>(status, `data`, message) {
    data class Hello (
        @SerializedMessage("hello")
        val hello: String
    )
}

编辑:自己的答案

好吧,我意识到 HelloResponse 实际上是一种浪费,因为我只是用它来访问 实际的 Hello class。 所以我所做的就是直接在 Retrofit2 服务中使用 Base class。 例如:

fun hello(): Call<BaseResponse<Hello>>

or

fun hellos(): Call<BaseResponse<List<Hello>>>

嗯,你必须在任何地方使用 BaseResponse 直接指定类型。也许创建 typeallias

或者您可以创建别名

typealias HelloResponse = BaseResponse<Hello>

typealias HellosResponse = BaseResponse<List<Hello>>

要使用 Gson 手动反序列化 json 字符串,您需要使用 TypeToken 参数而不是 class 类型。

val hello = Gson().fromJson<BaseResponse<Hello>>(jsonStr, object: TypeToken<BaseResponse<Hello>>(){}.type)

如果你使用

val hello = Gson().fromJson<BaseResponse<Hello>>(jsonStr, BaseResponse::class.java)

data 属性 不转换为 Hello 而是转换为 LinkedHashMap

注意: Retrofit2 的 GsonConverterFactory 内部使用了 TypeToken,所以没问题。

如果您不想为数据 subclass 编写 statusmessage 属性,那么您不能期望 subclass 具有带有 statusmessage 神奇地。

我强烈建议你将 BaseResponse 抽象化并使子class像下面这样

abstract class BaseResponse<T> {
    @SerializedName("status")
    abstract val status: Int

    @SerializedName("message")
    abstract val message: String

    @SerializedName("data")
    abstract val `data`: T
}

data class HelloResponse (
    override val status: Int,
    override val message: String,
    override val `data`: Hello,
) : BaseResponse<Hello>() {
    data class Hello (
        @SerializedMessage("hello")
        val hello: String
    )
}

您可以通过牺牲数据 classes 来实现它,而无需为 subclass 声明编写覆盖 val 属性。但是,您将失去数据 class.

提供的所有赏金
abstract class BaseResponse<T> {
    @SerializedName("status")
    abstract val status: Int

    @SerializedName("message")
    abstract val message: String

    @SerializedName("data")
    abstract val `data`: T
}

class HelloResponse: BaseResponse<Hello>() {
    data class Hello (
        @SerializedMessage("hello")
        val hello: String
    )
}

温馨提醒,如果class 属性 name 和json 属性 name 相同,则不需要使用@SerializedName 注释。