KotlinでJSONを解析する方法は?


121

サービスからかなり深いJSONオブジェクト文字列を受け取っていますが、これを解析してJSONオブジェクトに解析し、それをクラスにマップする必要があります。

JSON文字列をKotlinのオブジェクトに変換するにはどうすればよいですか?

その後、それぞれのクラスにマッピングするために、JacksonのStdDeserializerを使用しました。問題は、オブジェクトがクラスに逆シリアル化する必要があるプロパティを持っている瞬間に発生します。オブジェクトマッパーを取得できませんでした。少なくとも別のデシリアライザ内で、その方法がわかりませんでした。

助けてくれてありがとう。できれば、ネイティブで、必要な依存関係の数を減らすようにしているので、答えがJSON操作のみであり、解析で十分であれば、十分です。


2
私はJavaで開発していません。それは私が得ているエラーではありません。Kotlinでネイティブに効果的な構文解析を行う方法がわかりません。すべての検索は常にフレームワークにつながります。Javaにはorg.json.simpleがあります。IDEのオートコンプリート機能を信頼していますが、Kotlinはそうではありません。
AJ_1310 2017年

org.json.simpleパッケージはJavaにネイティブではありません。:私はそれがこのライブラリだと思うgithub.com/fangyidong/json-simple。必要に応じて、Kotlinでも使用できます(ただし、Jason Bourneが提案したklaxonライブラリーがKotlinに適している可能性があります)。
marstran 2017年

回答:


72

このライブラリを使用できます https://github.com/cbeust/klaxon

Klaxonは、KotlinでJSONを解析するための軽量ライブラリです。


85
ここの著者、質問/提案がある場合は私にメールしてください。
Cedric Beust 2017年

正しいパーサーを取得するには、どのJavaライブラリをインポートする必要がありますか?私はorg.json。*を試しましたが、Gradle設定で何かが欠けているに違いありません。Klaxonのドキュメントでは、(Javaライブラリーを知っているユーザーのように)想定が多すぎると思います。
マキス2017年

@CedricBeustあなたはsqliteでクラスオブジェクトを操作してみましたか?ここで推奨される練習はありますか?
Raju yourPepe

104

Kotlinでの解析の未来がkotlinx.serializationにあることは間違いありません。Kotlinライブラリの一部です。まだインキュベーター段階で執筆中です。

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
私がこれに持っている問題は、ジェネリックではほとんど使用できないことです。少なくとも私はそうする方法を理解していません。そして、私は確かにリフレクションを使いたくありません。
natronite

3
KotlinXシリアライゼーションはまだ実験段階にあるため、新しいリリースで重大な変更が導入されています。また、スレッドセーフではないため、複数のスレッドがJson(一般的な)の単一のインスタンスを使用しようとすると、JSONが破損する可能性があります。さらに、バグラベルに関するいくつかの未解決のGithub問題があります。したがって、私が言うであろう運用環境での使用には依然としてリスクがあります(潜在的な問題の修正に時間を費やして、頻繁に更新する予定がない限り)。このプロジェクトはKotlin Multiplatformプロジェクトにとって特に興味深いものですが、まだ安定していません。
Javad Sadeqzadeh

すでに重大な変更が行われているようで、JSONは現在Jsonと呼ばれています
xjcl

これはまた、追加の依存関係が必要なので、ガイドのリンク従ってください
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のものだと思いますか?私は、JVMのKotlinまたはJava標準ライブラリでそれを探していました。
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

25

使用できますGson

ステップ1

コンパイルを追加

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

ステップ2

jsonをKotlin BeanJsonToKotlinClassを使用して)に変換します

このような

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を与えます:文字列が必要ですが、行1の列700のパスで
BEGIN_OBJECTでした

最初に戻りデータを確認してください。@ SrishtiRoy
KeLiuyue

それは機能しましたが、私のjson応答が「categoories」のような場合:["Recommended"]、それから?
Srishti Roy

@SrishtiRoy応答は不正なJSONデータです。法的なJSONデータは、{または[
KeLiuyue

1
Gsonの問題は、ヌル可能性を無視することです。valプロパティは、簡単にすることができnull、それはJSONから欠けている場合。また、デフォルト値はまったく使用されません。
user3738870

21

これがあなたが必要とするものかどうかわかりませんが、これは私がやった方法です。

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
    }

次にjsonのサンプルを示します。

{"食品":[{"食品名": "りんご"、 "重量": "110"}]}


8
依存関係は何ですか?
ルイスソアレス

私はorg.jsonを使用しました。ここにリンクがあります: mvnrepository.com/artifact/org.json/json/20180813
markB

このメソッドでは、クラスにパラメータのないデフォルトのコンストラクタが必要です。:データクラスは、以下のようなコンストラクタ内のparamsを持っているどのような場合 data class SomeClass(val param1: Int, val param2: Int)
レイメンハオ

ヴァルカテゴリ=工ass(PARAM1 = foodJson.getJSONObject(I).getString( "FoodName")、PARAM2 = foodJson.getJSONObject(I).getInt( "重")):あなたは1行でこれを行うことができます@leimenghao
markB

本当にうまくいきます。言うまでもなく、のfor (i in 0 until foodJson!!.length()) {代わりに使用できますfor (i in 0..foodJson!!.length() - 1) {。それは同じことをし、それはかなり視覚的です
Arnyminer Z

12

私は個人的にKotlinのJacksonモジュールを使用しています。これは、ここにあります:jackson-module-kotlin

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

例として、非常に重い(フォーマット時に84k行)のPath of ExileスキルツリーのJSONを解析するコードを次に示します。

Kotlinコード:

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

さらに、intellijのJSON to Kotlinデータクラスプラグインを使用して、データクラスを生成できます。
Brooks DuBois

7

JSONをKotlinに変換するには、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をPOJOクラス(kotlinデータクラス)にマッピングするために、Android StudioのJSON to Kotlin Dataクラスコンバータープラグインを使用できます。このプラグインは、JSONに従ってKotlinデータクラスに注釈を付けます。

次に、GSONコンバーターを使用してJSONをKotlinに変換できます。

この完全なチュートリアルに従ってください: Kotlin Android JSON解析チュートリアル

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


0

少し遅れますが、何でも。

Kotlinのセマンティクスを利用する構造のようなJavaScriptよりもJSONを解析したい場合は、私が作成者であるJSONKrakenをお勧めします。

この件に関する提案や意見は高く評価されています!


-4

ここからdemeのソースをダウンロードします(android kotlinでのjson解析

この依存関係を追加します。

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()

        }

    })
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.