Як розібрати JSON у Котліні?


121

Я отримую досить глибокий рядок об'єкта JSON від служби, яку я повинен проаналізувати на об'єкт JSON, а потім зіставити його на класи.

Як я можу перетворити рядок JSON в об'єкт у Котліні?

Після цього для відображення відповідних класів я використовував StdDeserializer від Джексона. Проблема виникає в той момент, коли об’єкт мав властивості, які також довелося десеріалізувати в класи. Мені не вдалося отримати картографію об’єктів, принаймні я не знав як, всередині іншого десеріалізатора.

Заздалегідь дякую за будь-яку допомогу. Переважно, в основному, я намагаюся зменшити кількість залежностей, які мені потрібні, якщо відповідь стосується лише маніпуляцій JSON та їхнього розбору, цього буде достатньо.


2
Я не розвивався в Java. Це не помилка, яку я отримую. Я просто не знаю, як зробити ефективний синтаксичний аналіз в Котліні. Усі пошуки завжди ведуть до рамки. У Java є org.json.simple. Довіряючи функціям автозаповнення IDE, Котлін не робить.
— AJ_1310

Пакет org.json.simple не є власником Java. Я думаю, це бібліотека: github.com/fangyidong/json-simple . Ви можете використовувати його і з Котліном, якщо хочете (хоча бібліотека клаксонів, яку запропонував Джейсон Борн, може бути кращим вибором для Котліна).
— marstran

Погляньте на github.com/square/moshi . Про це є повідомлення в блозі на сайті medium.com/square-corner-blog/…
— Джеймс Мур

Відповіді:


72

Ви можете використовувати цю бібліотеку https://github.com/cbeust/klaxon

Klaxon - це легка бібліотека для розбору JSON у Котліні.


86
Автор тут, не соромтеся надіслати мені електронні листи, якщо у вас є питання / пропозиції
— Седрік Беуст

Які бібліотеки Java потрібно імпортувати, щоб отримати правильний Парсер? Я спробував org.json. *, Але мені, мабуть, щось не вистачає в налаштуваннях Gradle Я думаю, що документація Klaxon передбачає занадто багато (як користувач, що знає бібліотеки Java).
— Макіс

@CedricBeust Ви намагалися працювати з об’єктом класу з sqlite? будь-яка рекомендована практика тут?
— Раджу вашПепе

105

Немає сумніву, що майбутнє розбору в Котліні буде з kotlinx.serialization. Це частина бібліотек Котліна. Це ще під час написання в стадії інкубатора.

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
Проблема, яку я маю з цим, полягає в тому, що ти навряд чи можеш використовувати його з дженериками. Принаймні я не придумав, як це зробити. І я точно не хочу використовувати рефлексію.
— натроніт

3
KotlinX Serialization все ще знаходиться в експериментальній фазі, тому вони вносять надзвичайні зміни у нові випуски. Крім того, це не є безпечним для потоків, тому ваш JSON може бути пошкоджений, якщо кілька потоків спробують використовувати один екземпляр Json(це звичайно). Крім того, існує кілька відкритих проблем з Github з міткою про помилку. Отже, це все ще ризиковано використовувати у виробництві (якщо ви не готові витрачати час на виправлення потенційних проблем і не плануєте його часто оновлювати). Проект дійсно цікавий, особливо для проектів Kotlin Multiplatform, але він поки не стабільний.
— Джавад Садекзаде

Здається, вже
— відбулися

Це також вимагає додаткової залежності, тому перейдіть за посиланням для керівництва
— xjcl

34

Без зовнішньої бібліотеки (на Android)

Щоб проаналізувати це:

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

Використовуйте ці класи:

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")
}

Використання:

val foos = Response(jsonString)

2
Отже, якщо для цього не потрібні зовнішні бібліотеки, це означає, що org.json.JSONObject є частиною стандартної бібліотечної права?
— still_dreaming_1

@ still_dreaming_1 так, це "Додано в рівні API 1", пор. developer.android.com/reference/org/json/JSONObject.html
— frouo

Я думаю, що це Android? Я шукав його в стандартній бібліотеці Котліна або Java для JVM.
— still_dreaming_1

О так, я абсолютно вибачте, що забув згадати це у відповіді! Можливо, ви могли б використати, JsonObjectякщо ваш JVM працює під Java7 ( docs.oracle.com/javaee/7/api/javax/json/JsonObject.html )?
— frouo

О, я цього раніше не знайшов, дякую! Є також деякі інші пов'язані класи, наприклад, JsonReader. Здається, вони є частиною Java EE, але не Java SE. Я вивчу можливість переходу на Java EE.
— still_dreaming_1

26

Можна використовувати Gson.

Приклад

Крок 1

Додати компіляцію

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

Крок 2

Перетворити json в Kotlin Bean(використовувати JsonToKotlinClass )

Подобається це

Json дані

{
"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
    )
}

Крок 3

Використовуйте Gson

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

це дає мені java.lang.IllegalStateException: Очікуваний рядок, але BEGIN_OBJECT в рядку 1 стовпець 700 шляху
— Шрішті Рой

Спершу слід перевірити свої дані про повернення. @ SrishtiRoy
— KeLiuyue

він працював, але якщо моя відповідь на json схожа на "категорії": ["Рекомендовано"], тоді?
— Шрішті Рой

@SrishtiRoy відповідь є незаконними даними JSON. Юридичні дані JSON починаються з {або[
— KeLiuyue

1
Проблема Gson полягає в тому, що він нехтує нульовістю. valВластивість може бути легко , nullякщо він відсутній в форматі JSON. Також значення за замовчуванням взагалі не використовуються.
— користувач3738870

21

Не впевнений, що це те, що вам потрібно, але ось як я це зробив.

Використання імпорту 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
    }

Ось зразок json:

{"Foods": [{"FoodName": "Яблука", "Вага": "110"}]}


8
яка залежність?
— Луїс Соарес

Я використовував org.json. Ось посилання: mvnrepository.com/artifact/org.json/json/20180813
— markB

Цей метод вимагає, щоб у класу був конструктор за замовчуванням без парам. Що робити , якщо клас даних мають Params в конструкторі , як показано нижче: data class SomeClass(val param1: Int, val param2: Int).
— leimenghao

@leimenghao Ви можете зробити це в одному рядку: val категорії = SomeClass (param1 = foodJson.getJSONObject (i) .getString ("FoodName"), param2 = foodJson.getJSONObject (i) .getInt ("Вага"))
— markB

Працює дуже добре. Просто кажучи, ви можете використовувати for (i in 0 until foodJson!!.length()) {замість for (i in 0..foodJson!!.length() - 1) {. Це робить те саме, і це досить візуально
— Arnyminer Z

12

Я особисто використовую модуль Джексона для Котліна, який ви можете знайти тут: jackson-module-kotlin .

implementation "com.fasterxml.jackson.module:jackson-module-kotlin:$version"

Як приклад, ось код для розбору JSON майстерні Шляху вигнання, який є досить важким (84 форматів при форматуванні):

Котлін код:

package util

import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.module.kotlin.*
import java.io.File

data class SkillTreeData( val characterData: Map<String, CharacterData>, val groups: Map<String, Group>, val root: Root,
                          val nodes: List<Node>, val extraImages: Map<String, ExtraImage>, val min_x: Double,
                          val min_y: Double, val max_x: Double, val max_y: Double,
                          val assets: Map<String, Map<String, String>>, val constants: Constants, val imageRoot: String,
                          val skillSprites: SkillSprites, val imageZoomLevels: List<Int> )


data class CharacterData( val base_str: Int, val base_dex: Int, val base_int: Int )

data class Group( val x: Double, val y: Double, val oo: Map<String, Boolean>?, val n: List<Int> )

data class Root( val g: Int, val o: Int, val oidx: Int, val sa: Int, val da: Int, val ia: Int, val out: List<Int> )

data class Node( val id: Int, val icon: String, val ks: Boolean, val not: Boolean, val dn: String, val m: Boolean,
                 val isJewelSocket: Boolean, val isMultipleChoice: Boolean, val isMultipleChoiceOption: Boolean,
                 val passivePointsGranted: Int, val flavourText: List<String>?, val ascendancyName: String?,
                 val isAscendancyStart: Boolean?, val reminderText: List<String>?, val spc: List<Int>, val sd: List<String>,
                 val g: Int, val o: Int, val oidx: Int, val sa: Int, val da: Int, val ia: Int, val out: List<Int> )

data class ExtraImage( val x: Double, val y: Double, val image: String )

data class Constants( val classes: Map<String, Int>, val characterAttributes: Map<String, Int>,
                      val PSSCentreInnerRadius: Int )

data class SubSpriteCoords( val x: Int, val y: Int, val w: Int, val h: Int )

data class Sprite( val filename: String, val coords: Map<String, SubSpriteCoords> )

data class SkillSprites( val normalActive: List<Sprite>, val notableActive: List<Sprite>,
                         val keystoneActive: List<Sprite>, val normalInactive: List<Sprite>,
                         val notableInactive: List<Sprite>, val keystoneInactive: List<Sprite>,
                         val mastery: List<Sprite> )

private fun convert( jsonFile: File ) {
    val mapper = jacksonObjectMapper()
    mapper.configure( DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT, true )

    val skillTreeData = mapper.readValue<SkillTreeData>( jsonFile )
    println("Conversion finished !")
}

fun main( args : Array<String> ) {
    val jsonFile: File = File( """rawSkilltree.json""" )
    convert( jsonFile )

JSON (неформатований): http://filebin.ca/3B3reNQf3KXJ/rawSkilltree.json

З огляду на ваш опис, я вважаю, що він відповідає вашим потребам.


1
На відміну від Клаксона (у нього була помилка, коли я спробував), Джексон насправді працює :)
— redsk

Крім того, ви можете використовувати плагін класу даних JSON to Kotlin в intellij для створення для вас класів даних.
— Брукс Дюбуа

7

Для перетворення JSON в Котлін використовуйте http://www.json2kotlin.com/

Також ви можете використовувати плагін Android Studio. Файл> Налаштування, виберіть Pluginsу лівому дереві, натисніть "Огляд сховищ ...", пошук " JsonToKotlinClass ", виберіть його та натисніть зелену кнопку "Встановити".

підключати

Після перезавантаження AS ви можете використовувати його. Ви можете створити клас за допомогою File > New > JSON To Kotlin Class (JsonToKotlinClass). Інший спосіб - натиснути Alt + K.

введіть тут опис зображення

Тоді ви побачите діалогове вікно, щоб вставити JSON.

У 2018 році мені довелося додати package com.my.package_nameна початку заняття.


4

Поперше.

Ви можете використовувати плагін JSON для Kotlin Data Class Converter в Android Studio для відображення JSON в класи POJO (kotlin data class). Цей плагін буде анотувати ваш клас даних Kotlin згідно JSON.

Тоді ви можете використовувати конвертер GSON для перетворення JSON в Котлін.

Виконайте цей повний підручник: Kotlin Android JSON Parsing Tutorial

Якщо ви хочете розібрати json вручну.

val **sampleJson** = """
  [
  {
   "userId": 1,
   "id": 1,
   "title": "sunt aut facere repellat provident occaecati excepturi optio 
    reprehenderit",
    "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita"
   }]
   """

Код для розбору над масивом JSON та його об'єктом в індексі 0.

var jsonArray = JSONArray(sampleJson)
for (jsonIndex in 0..(jsonArray.length() - 1)) {
Log.d("JSON", jsonArray.getJSONObject(jsonIndex).getString("title"))
}

1

http://www.jsonschema2pojo.org/ Привіт, ви можете використовувати цей веб-сайт для перетворення json в pojo.
управління + Alt + зсув + k

Після цього ви можете вручну перетворити цей модельний клас у модель класу kotlin. за допомогою наведеного вище ярлика.


1
Він перетвориться на Java.
— CoolMind

0

Трохи пізно, але що б там не було.

Якщо ви віддаєте перевагу розбору JSON перед JavaScript, як конструкції, що використовують семантику Котліна , я рекомендую JSONKraken , автором якого я є.

Пропозиції та думки з цього приводу дуже оцінені!


-4

Завантажте джерело deme звідси ( Json розбирає в android kotlin )

Додайте цю залежність:

compile 'com.squareup.okhttp3:okhttp:3.8.1'

Функція виклику api:

 fun run(url: String) {
    dialog.show()
    val request = Request.Builder()
            .url(url)
            .build()

    client.newCall(request).enqueue(object : Callback {
        override fun onFailure(call: Call, e: IOException) {
            dialog.dismiss()

        }

        override fun onResponse(call: Call, response: Response) {
            var str_response = response.body()!!.string()
            val json_contact:JSONObject = JSONObject(str_response)

            var jsonarray_contacts:JSONArray= json_contact.getJSONArray("contacts")

            var i:Int = 0
            var size:Int = jsonarray_contacts.length()

            al_details= ArrayList();

            for (i in 0.. size-1) {
                var json_objectdetail:JSONObject=jsonarray_contacts.getJSONObject(i)


                var model:Model= Model();
                model.id=json_objectdetail.getString("id")
                model.name=json_objectdetail.getString("name")
                model.email=json_objectdetail.getString("email")
                model.address=json_objectdetail.getString("address")
                model.gender=json_objectdetail.getString("gender")

                al_details.add(model)


            }

            runOnUiThread {
                //stuff that updates ui
                val obj_adapter : CustomAdapter
                obj_adapter = CustomAdapter(applicationContext,al_details)
                lv_details.adapter=obj_adapter
            }

            dialog.dismiss()

        }

    })
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.