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.