2017-04-23 2 views
3

Dans une application Android, je dois désérialiser les données Json pour les classes de données Kotlin, avec un seul niveau d'abstraction. Mais je n'ai aucune idée, de placer les propriétés correctes dans les constructeurs.Comment désérialiser les classes de données héritées de Kotlin avec Gson

En version simple, disons que j'ai une forme:

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

avec deux dérivations

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

et

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

Donc, mon objectif est de ne pas instancier un Forme. Donc, au lieu de cela, désérialisez toujours ses dérivations. Plus tard, je dois gérer des propriétés de collecte dans d'autres classes comme:

val shapes: List<Shape> 

, mais je dois aussi connaître le type dérivé de chaque élément.

Lorsque je tente de désérialiser l'exemple avec Gson

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

Je reçois toujours un 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) 

Est-il possible de désérialiser cette classe correctement sans écrire une coutume Gson TypeAdapter ou perdre avantages de classe de données?

Merci

Répondre

1

Etes-vous sûr que c'est un problème Gson avec les classes de données? Cela devrait fonctionner correctement avec eux, seuls les champs non valables peuvent être un problème.

Votre erreur indique que vous avez des champs avec le même nom.
S'il y a un domaine particulier que vous ne voulez pas vous inclure devez annoter avec @Transient

5

Les deux Shape et Square champs x et déclarent y. Une instance de Square stocke en fait la valeur pour x et y deux fois. Pour éviter cela, vous pouvez supprimer x et y du constructeur Shape et les déclarer abstract. La même chose vaut pour Circle .: par exemple

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 va maintenant être en mesure de sérialisation avec succès et désérialiser Circle et Square objets.

+1

Merci. C'est la solution que je cherchais. – elcolto

1

Si vous n'êtes pas encore en mesure de convertir la classe de base en Kotlin, l'annotation @Transient a fonctionné pour moi.

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)