Classe de données Kotlin de Json utilisant GSON

105

J'ai une classe Java POJO comme celle-ci:

class Topic {
    @SerializedName("id")
    long id;
    @SerializedName("name")
    String name;
}

et j'ai une classe de données Kotlin comme celle-ci

 data class Topic(val id: Long, val name: String)

Comment fournir le json keyà des variables kotlin data classsimilaires à l' @SerializedNameannotation dans les variables Java?

Erluxman
la source
1
Comment l'avez-vous fait en Java? Montrez un exemple.
nhaarman
Qu'est-ce qu'un sélecteur json?
voddan
@voddan ce que je voulais dire par ces sélecteurs json, c'est que les chaînes que je peux utiliser pour sélectionner un objet / tableau json particulier: dans mon cas "topic", "id", "image". J'espère que je vous l'ai expliqué. Merci :)
erluxman
@nhaarman J'ai édité la question, j'espère que c'est ce que vous voulez dire
erluxman

Réponses:

227

Classe de données:

data class Topic(
  @SerializedName("id") val id: Long, 
  @SerializedName("name") val name: String, 
  @SerializedName("image") val image: String,
  @SerializedName("description") val description: String
)

vers JSON:

val gson = Gson()
val json = gson.toJson(topic)

depuis JSON:

val json = getJson()
val topic = gson.fromJson(json, Topic::class.java)
Anton Holovin
la source
36
N'utilisez les annotations qu'en cas d'incompatibilité de nom de variable. Sinon, ouais, pas nécessaire
Vik
3
À mon avis, les annotations nous permettent d'avoir des classes qui, une fois sérialisées, peuvent être exclues ou inclure les variables. Très utile lorsqu'il est utilisé avec la modernisation. Cela n'envoie pas de déchets au serveur. De plus, lorsqu'il y a des changements dans les noms des variables côté serveur, il est plus pénible de le changer directement dans la variable de classe que dans l'annotation.
Deneb Chorny
11
@Vik, une chose à noter est que vos noms de variables peuvent éventuellement être obscurcis (comme dans une application Android) mais l'annotation restera intacte
Caleb_Allen
@AntonGolovin Je ne parviens pas à transmettre ma classe de données à partir de la méthode Json, dois-je déclarer ma classe de données dans un fichier java?
Ravi Yadav
Si vous faites cela, je pense que vous perdrez le format JSON, ce qui peut provoquer une exception IllegalStateException sur la route
portfoliobuilder
19

Basé sur la réponse d' Anton Golovin

Détails

  • Version Gson: 2.8.5
  • Android Studio 3.1.4
  • Version Kotlin: 1.2.60

Solution

Créez des données de classe et héritez de l' interface JSONConvertable

interface JSONConvertable {
     fun toJSON(): String = Gson().toJson(this)
}

inline fun <reified T: JSONConvertable> String.toObject(): T = Gson().fromJson(this, T::class.java)

Usage

Classe de données

data class User(
    @SerializedName("id") val id: Int,
    @SerializedName("email") val email: String,
    @SerializedName("authentication_token") val authenticationToken: String) : JSONConvertable

Depuis JSON

val json = "..."
val object = json.toObject<User>()

Vers JSON

val json = object.toJSON()
Vasily Bodnarchuk
la source
Pourquoi utilisez-vous l' SerializedNameannotation au lieu de la stratégie de dénomination de champ, Vasily?
peterchaula
2
@Peter car @SerializedNameme permettra d'utiliser des noms personnalisés des variables qui peuvent ne pas correspondre à la clé json. Et oui, vous ne pouvez pas utiliser @SerializedNamesi vous n'en avez pas besoin.
Vasily Bodnarchuk
2

Vous pouvez utiliser similaire dans la classe Kotlin

class InventoryMoveRequest {
    @SerializedName("userEntryStartDate")
    @Expose
    var userEntryStartDate: String? = null
    @SerializedName("userEntryEndDate")
    @Expose
    var userEntryEndDate: String? = null
    @SerializedName("location")
    @Expose
    var location: Location? = null
    @SerializedName("containers")
    @Expose
    var containers: Containers? = null
}

Et aussi pour la classe imbriquée, vous pouvez utiliser la même chose comme s'il y a un objet imbriqué. Fournissez simplement le nom de sérialisation de la classe.

@Entity(tableName = "location")
class Location {

    @SerializedName("rows")
    var rows: List<Row>? = null
    @SerializedName("totalRows")
    var totalRows: Long? = null

}

donc si obtenir une réponse du serveur, chaque clé sera mappée avec JOSN.

Alos, convertissez la liste en JSON:

val gson = Gson()
val json = gson.toJson(topic)

ndroid convertir de JSON en objet:

val json = getJson()
val topic = gson.fromJson(json, Topic::class.java)
Pawan Soni
la source