Как десериализовать унаследованные классы данных Kotlin с помощью Gson

В Android-приложении мне нужно десериализовать данные Json для классов данных Kotlin с одним уровнем абстракции. Но я не знаю, разместить правильные свойства в конструкторах.

Как простая версия, допустим, у меня есть Shape:

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) 

Есть ли возможность десериализовать эти классы правильно, не записывая пользовательский GScript TypeAdapter или теряя преимущества класса данных?

благодаря

И Shape и Square объявляют поля x и y . Экземпляр Square фактически сохраняет значение для x и y дважды. Чтобы этого избежать, вы можете удалить x и y из конструктора Shape и объявить их abstract . То же самое касается Circle например:

 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 .

Вы уверены, что это проблема Gson с классами данных? Он должен работать с ними правильно, но могут быть проблемой только поля с недействительными значениями.

Ваша ошибка указывает, что в нем есть поля с тем же именем.
Если есть какое-то конкретное поле, которое вы не хотите включать, вы должны аннотировать его с помощью @Transient

Если вы еще не можете преобразовать базовый класс в 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)