如何为多个类似的 API JSON 响应结构的多个数据类编写 Kotlin 基类 - 已关闭
所有 API JSON 响应都将具有以下结构:
{
"status": <Integer>
"data": <Object or List of Objects>
"message": <String>
}
唯一更改的属性是“数据”,它可以是任何对象或对象列表。 那么有没有办法创建像
open class BaseResponse<T> (
@SerializedName("status")
val status: Int,
@SerializedName("data")
abstract val `data`: T,
@SerializedName("message")
val message: String
)
响应类这样的 BaseResponse 类
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
属性,这样我就不必编写我编写的每个响应子数据类的状态和消息属性。我不想在子类中写入状态和消息并将其传递给基类,因为我仍然会写入这两个属性,因此与创建具有状态和消息的数据类没有区别。
所以不能像
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类。 所以我所做的就是直接在Retrofit2服务中使用Base类。 例如:
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 参数而不是类类型。
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,所以没问题。
All the API JSON responses would have the following structure:
{
"status": <Integer>
"data": <Object or List of Objects>
"message": <String>
}
the only property that changes is the 'data', which can be any object or list of object.
So is there a way to create a BaseResponse class like
open class BaseResponse<T> (
@SerializedName("status")
val status: Int,
@SerializedName("data")
abstract val `data`: T,
@SerializedName("message")
val message: String
)
and the response 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
)
}
What i really want is to only override the data
property, so that i don't have to write status and message property for each Response sub data class i write. I dont want to write status and message in my sub class and pass it to base class, cause i'd still write both the properties, so no difference than creating a data class with status and message.
so cannot be like
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
)
}
Edit: Own Answer
Well I realized that the HelloResponse is actually a waste since i'm only using it to access the actual Hello class.
So what i did was to use the Base class directly in Retrofit2 service.
Eg:
fun hello(): Call<BaseResponse<Hello>>
or
fun hellos(): Call<BaseResponse<List<Hello>>>
Well you have to directly specify the type with BaseResponse everywhere you use it. Maybe create typeallias
Or you can create alias
typealias HelloResponse = BaseResponse<Hello>
typealias HellosResponse = BaseResponse<List<Hello>>
To manually deserialize json string with Gson, you need to use TypeToken parameter instead of class type.
val hello = Gson().fromJson<BaseResponse<Hello>>(jsonStr, object: TypeToken<BaseResponse<Hello>>(){}.type)
If you use
val hello = Gson().fromJson<BaseResponse<Hello>>(jsonStr, BaseResponse::class.java)
The data
property doesn't convert to Hello instead converts to LinkedHashMap
Note:
Retrofit2's GsonConverterFactory uses TypeToken internally, so no problem.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

如果您不想为数据子类编写
status
和message
属性,那么您不能期望子类具有带有status
和的构造函数>消息
神奇地。我强烈建议您将 BaseResponse 抽象化并创建子类,如下所示
您可以通过牺牲数据类的方式实现它,而无需为子类声明编写重写 val 属性。但是,您将失去数据类提供的所有奖励。
温馨提示,如果类属性名称和 json 属性名称相同,则不需要使用
@SerializedName
注解。If you don't want to write
status
andmessage
properties for data subclasses then you cannot expect subclass to have a constructor withstatus
andmessage
magically.I strongly suggest you to make BaseResponse abstract and make subclasses like following
You can achieve it in a way you don't need to write override val properties for subclass declarations by sacrificing data classes. However you lose all bounties provided by data class.
Just a kind reminder, you don't need to use
@SerializedName
annotation if class property name and json property name are same.