10

在 Android 应用程序中,我需要为 Kotlin 数据类反序列化 Json 数据,具有单一抽象级别。但我不知道在构造函数中放置正确的属性。

作为一个简单的版本,假设我有一个形状:

abstract class Shape(open val x: Int, open val y: Int)

有两个推导

data class Circle(val radius: Int, override val x: Int, override val y: Int): Shape(x, y)

data class Square(val width: Int, override val x: Int, override val y: Int): Shape(x, y)

所以我的目标是,不实例化一个形状。所以,总是反序列化它的派生。稍后我需要处理其他类中的一些集合属性,例如:

val shapes: List<Shape>

但我还必须知道每个元素的派生类型。

当我尝试使用 Gson 反序列化给定示例时

val square = gson.fromJson(SQUARE_JSON, Square::class.java)

我总是得到一个 IllegalArgumentException

java.lang.IllegalArgumentException: class com.example.shapes.model.Square declares multiple JSON fields named x

at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:170)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:100)
at com.google.gson.Gson.getAdapter(Gson.java:423)
at com.google.gson.Gson.fromJson(Gson.java:886)
at com.google.gson.Gson.fromJson(Gson.java:852)
at com.google.gson.Gson.fromJson(Gson.java:801)
at com.google.gson.Gson.fromJson(Gson.java:773)

是否有可能在不编写自定义 Gson TypeAdapter 或失去数据类优势的情况下正确反序列化此类?

谢谢

4

3 回答 3

15

Shape和声明Square字段xy。的一个实例Square实际上存储了xy两次的值。为避免这种情况,您可以从构造函数中删除xand并将它们声明为. 例如:yShapeabstractCircle

abstract class Shape {
    abstract val x: Int
    abstract val y: Int
}

data class Circle(val radius: Int, override val x: Int, override val y: Int) : Shape()

data class Square(val width: Int, override val x: Int, override val y: Int) : Shape()

Gson 现在将能够成功地序列化和反序列化Circle对象Square

于 2017-04-24T15:36:13.767 回答
4

如果您还不能将基类转换为 Kotlin,那么@Transient注释对我有用。

data class Circle(val radius: Int, 
    @Transient val x: Int, 
    @Transient val y: Int): Shape(x, y)

data class Square(val width: Int, 
    @Transient val x: Int, 
    @Transient val y: Int): Shape(x, y)
于 2017-06-26T19:52:30.167 回答
1

你确定这是数据类的 Gson 问题吗?它应该可以正确使用它们,只有不可为空的字段可能是一个问题。

您的错误表明您有相同名称的字段。
如果您不想包含任何特定字段,则必须对其进行注释@Transient

于 2017-04-24T05:40:57.957 回答