160 votes

Comment analyser JSON en Kotlin ?

Je reçois d'un service une chaîne d'objets JSON assez profonde que je dois analyser pour en faire un objet JSON, puis l'associer à des classes.

Comment transformer une chaîne JSON en objet en Kotlin ?

Après cela, le mappage vers les classes respectives, j'ai utilisé StdDeserializer de Jackson. Le problème est apparu au moment où l'objet avait des propriétés qui devaient également être désérialisées en classes. Je n'étais pas en mesure d'obtenir le mappeur d'objet, du moins je ne savais pas comment, à l'intérieur d'un autre deserializer.

De préférence, en natif, j'essaie de réduire le nombre de dépendances dont j'ai besoin, donc si la réponse ne concerne que la manipulation et l'analyse de JSON, ce sera suffisant.

2 votes

Je n'ai pas développé en Java. Ce n'est pas une erreur que j'obtiens. C'est juste que je ne sais pas comment faire un parsing efficace en Kotlin de manière native. Toutes les recherches mènent toujours à un framework. Java a un org.json.simple. Si l'on fait confiance aux fonctions d'autocomplétion de l'IDE, Kotlin n'en a pas.

0 votes

Le paquet org.json.simple n'est pas natif à Java. Je suppose que c'est cette bibliothèque : github.com/fangyidong/json-simple . Vous pouvez également l'utiliser avec Kotlin si vous le souhaitez (bien que la bibliothèque klaxon suggérée par Jason Bourne soit un meilleur choix pour Kotlin).

0 votes

Jetez un coup d'œil à github.com/square/moshi . Il y a un article de blog à ce sujet sur medium.com/square-corner-blog/

131voto

Il ne fait aucun doute que l'avenir de l'analyse syntaxique dans Kotlin passera par kotlinx.serialization. Elle fait partie des bibliothèques Kotlin. La version 1.0 de kotlinx.serialization est enfin disponible.

https://github.com/Kotlin/kotlinx.serialization

import kotlinx.serialization.*
import kotlinx.serialization.json.JSON

@Serializable
data class MyModel(val a: Int, @Optional val b: String = "42")

fun main(args: Array<String>) {

    // serializing objects
    val jsonData = JSON.stringify(MyModel.serializer(), MyModel(42))
    println(jsonData) // {"a": 42, "b": "42"}

    // serializing lists
    val jsonList = JSON.stringify(MyModel.serializer().list, listOf(MyModel(42)))
    println(jsonList) // [{"a": 42, "b": "42"}]

    // parsing data back
    val obj = JSON.parse(MyModel.serializer(), """{"a":42}""")
    println(obj) // MyModel(a=42, b="42")
}

3 votes

Le problème que j'ai avec cela est que vous pouvez difficilement l'utiliser avec les génériques. Du moins, je n'ai pas encore trouvé comment le faire. Et je ne veux certainement pas utiliser la réflexion.

5 votes

La sérialisation de KotlinX est encore en phase expérimentale, ce qui explique que des changements importants soient introduits dans les nouvelles versions. De plus, elle n'est pas thread-safe, donc votre JSON pourrait être corrompu si plusieurs threads essayent d'utiliser une seule instance de Json (c'est courant). De plus, il y a plusieurs problèmes ouverts sur Github avec l'étiquette de bogue. Il est donc encore risqué de l'utiliser en production (à moins que vous ne soyez prêt à passer du temps à corriger les problèmes potentiels et que vous ne prévoyiez pas de le mettre à jour fréquemment). Le projet est en effet intéressant surtout pour les projets Kotlin Multiplatform, mais il n'est pas encore stable.

1 votes

Il semble qu'il y ait déjà un changement de rupture, JSON s'appelle désormais Json.

87voto

Jason Bourne Points 4213

Vous pouvez utiliser cette bibliothèque https://github.com/cbeust/klaxon

Klaxon est une bibliothèque légère pour analyser JSON en Kotlin.

128 votes

Auteur ici, n'hésitez pas à m'envoyer un courriel si vous avez des questions/suggestions.

0 votes

Je l'ai essayé aujourd'hui après deux jours à me farcir d'autres bibliothèques, et ça marche vraiment bien. Le support polymorphe et la documentation ont l'air bien aussi, après les collections c'est la deuxième chose que je teste toujours. Super paquet @Cedric !

0 votes

Pourquoi utiliser une bibliothèque quand un support intégré est disponible ?

44voto

Frouo Points 1348

Sans bibliothèque externe (sur Android)

Pour analyser ça :

val jsonString = """
    {
       "type":"Foo",
       "data":[
          {
             "id":1,
             "title":"Hello"
          },
          {
             "id":2,
             "title":"World"
          }
       ]
    }        
"""

Utilisez ces classes :

import org.json.JSONObject

class Response(json: String) : JSONObject(json) {
    val type: String? = this.optString("type")
    val data = this.optJSONArray("data")
            ?.let { 0.until(it.length()).map { i -> it.optJSONObject(i) } } // returns an array of JSONObject
            ?.map { Foo(it.toString()) } // transforms each JSONObject of the array into Foo
}

class Foo(json: String) : JSONObject(json) {
    val id = this.optInt("id")
    val title: String? = this.optString("title")
}

Utilisation :

val foos = Response(jsonString)

4 votes

Donc, si cela ne nécessite aucune bibliothèque externe, cela devrait signifier que org.json.JSONObject fait partie de la bibliothèque standard, n'est-ce pas ?

1 votes

@still_dreaming_1 oui c'est ça, "Ajouté dans l'API niveau 1", cf. developer.Android.com/reference/org/json/JSONObject.html

2 votes

Je suppose que c'est un truc Android ? Je le cherchais dans la bibliothèque standard Kotlin ou Java pour la JVM.

37voto

KeLiuyue Points 6175

Vous pouvez utiliser Gson .

Exemple

Étape 1

Ajouter la compilation

compile 'com.google.code.gson:gson:2.8.2'

Étape 2

Convertir json en Kotlin Bean (utiliser JsonToKotlinClass )

Comme ceci

Json données

{
"timestamp": "2018-02-13 15:45:45",
"code": "OK",
"message": "user info",
"path": "/user/info",
"data": {
    "userId": 8,
    "avatar": "/uploads/image/20180115/1516009286213053126.jpeg",
    "nickname": "",
    "gender": 0,
    "birthday": 1525968000000,
    "age": 0,
    "province": "",
    "city": "",
    "district": "",
    "workStatus": "Student",
    "userType": 0
},
"errorDetail": null
}

Kotlin Bean

class MineUserEntity {

    data class MineUserInfo(
        val timestamp: String,
        val code: String,
        val message: String,
        val path: String,
        val data: Data,
        val errorDetail: Any
    )

    data class Data(
        val userId: Int,
        val avatar: String,
        val nickname: String,
        val gender: Int,
        val birthday: Long,
        val age: Int,
        val province: String,
        val city: String,
        val district: String,
        val workStatus: String,
        val userType: Int
    )
}

Étape 3

Utilice Gson

var gson = Gson()
var mMineUserEntity = gson?.fromJson(response, MineUserEntity.MineUserInfo::class.java)

0 votes

Le plugin ne fonctionne pas pour les objets JSON imbriqués pour le moment.

2 votes

Le problème avec Gson est qu'il ne tient pas compte de la nullité. A val peut facilement être null s'il est absent du JSON. De plus, les valeurs par défaut ne sont pas du tout utilisées.

0 votes

@user3738870 avez-vous trouvé une meilleure alternative ? Je suis frustré par ce comportement de tous les parseurs que j'essaie.

30voto

markB Points 159

Je ne sais pas si c'est ce dont vous avez besoin, mais c'est ainsi que j'ai procédé.

Utilisation de l'import org.json.JSONObject :

    val jsonObj = JSONObject(json.substring(json.indexOf("{"), json.lastIndexOf("}") + 1))
    val foodJson = jsonObj.getJSONArray("Foods")
    for (i in 0..foodJson!!.length() - 1) {
        val categories = FoodCategoryObject()
        val name = foodJson.getJSONObject(i).getString("FoodName")
        categories.name = name
    }

Voici un échantillon du fichier json :

{"Aliments" : { {"FoodName" : "Apples", "Weight" : "110" } ]}.

11 votes

Quelle est la dépendance ?

1 votes

J'ai utilisé org.json. Voici le lien : mvnrepository.com/artifact/org.json/json/20180813

0 votes

Cette méthode exige que la classe ait un constructeur par défaut sans aucun paramètre. Que se passe-t-il si la classe de données a des paramètres dans le constructeur comme ci-dessous : data class SomeClass(val param1: Int, val param2: Int) .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X