如何为多个相似的 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 编写 status
和 message
属性,那么您不能期望 subclass 具有带有 status
和 message
神奇地。
我强烈建议你将 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
注释。
所有 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 编写 status
和 message
属性,那么您不能期望 subclass 具有带有 status
和 message
神奇地。
我强烈建议你将 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
注释。