Kotlin에서 JSON을 파싱하는 방법은 무엇입니까?


121

서비스에서 JSON 개체로 구문 분석 한 다음 클래스에 매핑해야하는 매우 깊은 JSON 개체 문자열을 받았습니다.

Kotlin에서 JSON 문자열을 객체로 변환하려면 어떻게해야하나요?

그 후 각 클래스에 매핑 한 후 Jackson의 StdDeserializer를 사용했습니다. 문제는 객체에 클래스로 역 직렬화되어야하는 속성이있는 순간에 발생합니다. 나는 객체 매퍼를 얻을 수 없었습니다. 적어도 다른 deserializer 내부에서 방법을 몰랐습니다.

도움을 주셔서 미리 감사드립니다. 가급적이면 기본적으로 필요한 종속성 수를 줄이려고 노력하고 있으므로 대답이 JSON 조작 및 구문 분석에만 해당된다면 충분할 것입니다.


2
Java로 개발하지 않았습니다. 내가받는 오류가 아닙니다. Kotlin에서 기본적으로 효과적인 파싱을 수행하는 방법을 모르겠습니다. 모든 검색은 항상 프레임 워크로 이어집니다. Java에는 org.json.simple이 있습니다. IDE의 자동 완성 기능을 신뢰하는 Kotlin은 그렇지 않습니다.
— AJ_1310

org.json.simple 패키지는 Java의 기본 패키지가 아닙니다. 이 라이브러리 인 것 같습니다 : github.com/fangyidong/json-simple . 원한다면 Kotlin과 함께 사용할 수도 있습니다 (Jason Bourne이 제안한 klaxon 라이브러리가 Kotlin에 더 나은 선택 일 수 있음).
— marstran

github.com/square/moshi를 살펴보세요 . medium.com/square-corner-blog/… 에 블로그 게시물이 있습니다.
— 제임스 무어

답변:


72

이 라이브러리를 사용할 수 있습니다. https://github.com/cbeust/klaxon을

Klaxon은 Kotlin에서 JSON을 파싱하는 경량 라이브러리입니다.


86
여기에서 작성하세요. 질문 / 제안이 있으면 언제든지 이메일을 보내주세요.
— Cedric Beust

올바른 파서를 가져 오려면 어떤 Java 라이브러리를 가져와야합니까? org.json. *을 시도했지만 Gradle 설정에 뭔가 빠진 것 같습니다. Klaxon 문서는 사용자가 Java 라이브러리를 알고있는 것처럼 너무 많이 가정한다고 생각합니다.
— Makis

@CedricBeust sqlite로 클래스 객체 작업을 시도 했습니까? 여기에 권장되는 연습이 있습니까?
— Raju yourPepe 2017

105

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

안드로이드 문제인 것 같아요? JVM 용 Kotlin 또는 Java 표준 라이브러리에서 찾고있었습니다.
— still_dreaming_1 jul.

아, 물론입니다. 대답에 언급하는 것을 잊었 네요! JsonObjectJVM이 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 제공 : 라인 1 열 (700) 경로에 BEGIN_OBJECT 문자열 예상되었지만
— Srishti 로이

먼저 수익 데이터를 확인해야 @ SrishtiRoy.
— KeLiuyue

작동했지만 내 json 응답이 "categories": [ "Recommended"]와 같으면 다음?
— Srishti Roy

@SrishtiRoy 응답이 잘못된 JSON 데이터입니다. 법률 JSON 데이터로 시작 {또는[
— KeLiuyue

1
Gson의 문제는 null 허용 여부를 무시한다는 것입니다. 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의 샘플입니다.

{ "음식": [{ "FoodName": "사과", "무게": "110"}]}


8
의존성은 무엇입니까?
— Luís Soares

org.json을 사용했습니다. 링크 : mvnrepository.com/artifact/org.json/json/20180813
— markB

이 메서드를 사용하려면 클래스에 매개 변수가없는 기본 생성자가 있어야합니다. 데이터 클래스에 아래와 같이 생성자에 매개 변수가있는 경우 : data class SomeClass(val param1: Int, val param2: Int).
— leimenghao

@leimenghao 한 줄로이 작업을 수행 할 수 있습니다. val categories = SomeClass (param1 = foodJson.getJSONObject (i) .getString ( "FoodName"), param2 = foodJson.getJSONObject (i) .getInt ( "Weight"))
— markB

정말 잘 작동합니다. 즉, for (i in 0 until foodJson!!.length()) {대신 사용할 수 있습니다 for (i in 0..foodJson!!.length() - 1) {.
— 똑같고

12

저는 개인적으로 jackson-module-kotlin에서 찾을 수있는 Kotlin 용 Jackson 모듈을 사용합니다 .

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

예를 들어, 다음은 상당히 무거운 Exile 스킬 트리 경로의 JSON을 구문 분석하는 코드입니다 (포맷시 84k 줄).

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
Klaxon (내가 시도했을 때 버그가 있음)과
— 달리

또한 intellij에서 JSON to Kotlin 데이터 클래스 플러그인을 사용하여 데이터 클래스를 생성 할 수 있습니다.
— Brooks DuBois 2019

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

가장 먼저.

Android 스튜디오에서 JSON to Kotlin 데이터 클래스 변환기 플러그인을 사용하여 POJO 클래스 (kotlin 데이터 클래스)에 JSON 매핑 할 수 있습니다. 이 플러그인은 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"))
}

1

http://www.jsonschema2pojo.org/ 안녕하세요이 웹 사이트를 사용하여 json을 pojo로 변환 할 수 있습니다.
Ctrl + Alt + Shift + k

그런 다음 해당 모델 클래스를 kotlin 모델 클래스로 수동으로 변환 할 수 있습니다. 위의 바로 가기의 도움으로.


1
Java로 변환됩니다.
— CoolMind

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.