I'm receiving a quite deep JSON object string from a service which I must parse to a JSON object and then map it to classes.
How can I transform a JSON string to object in Kotlin?
After that the mapping to the respective classes, I was using StdDeserializer from Jackson. The problem arises at the moment the object had properties that also had to be deserialized into classes. I was not able to get the object mapper, at least I didn't know how, inside another deserializer.
Thanks in advance for any help. Preferably, natively, I'm trying to reduce the number of dependencies I need so if the answer is only for JSON manipulation and parsing it'd be enough.
You can use this library https://github.com/cbeust/klaxon
Klaxon is a lightweight library to parse JSON in Kotlin.
To parse this:
val jsonString = """
{
"type":"Foo",
"data":[
{
"id":1,
"title":"Hello"
},
{
"id":2,
"title":"World"
}
]
}
"""
Use these 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")
}
Usage:
val foos = Response(jsonString)
http://www.jsonschema2pojo.org/
Hi you can use this website to convert json to pojo.
control+Alt+shift+k
After that you can manualy convert that model class to kotlin model class. with the help of above shortcut.
To convert JSON to Kotlin use http://www.json2kotlin.com/
Also you can use Android Studio plugin. File > Settings, select Plugins
in left tree, press "Browse repositories...", search "JsonToKotlinClass", select it and click green button "Install".
After AS restart you can use it. You can create a class with File > New > JSON To Kotlin Class (JsonToKotlinClass)
. Another way is to press Alt + K.
Then you will see a dialog to paste JSON.
In 2018 I had to add package com.my.package_name
at the beginning of a class.
I personally use the Jackson module for Kotlin that you can find here: jackson-module-kotlin.
implementation "com.fasterxml.jackson.module:jackson-module-kotlin:$version"
As an example, here is the code to parse the JSON of the Path of Exile skilltree which is quite heavy (84k lines when formatted) :
Kotlin code:
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 (not-formatted): http://filebin.ca/3B3reNQf3KXJ/rawSkilltree.json
Given your description, I believe it matches your needs.
Download the source of deme from here(Json parsing in android kotlin)
Add this dependency:
compile 'com.squareup.okhttp3:okhttp:3.8.1'
Call api function:
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()
}
})
First of all.
You can use JSON to Kotlin Data class converter plugin in Android Studio for JSON mapping to POJO classes (kotlin data class). This plugin will annotate your Kotlin data class according to JSON.
Then you can use GSON converter to convert JSON to Kotlin.
Follow this Complete tutorial: Kotlin Android JSON Parsing Tutorial
If you want to parse json manually.
val **sampleJson** = """
[
{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio
reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita"
}]
"""
Code to Parse above JSON Array and its object at index 0.
var jsonArray = JSONArray(sampleJson)
for (jsonIndex in 0..(jsonArray.length() - 1)) {
Log.d("JSON", jsonArray.getJSONObject(jsonIndex).getString("title"))
}
Not sure if this is what you need but this is how I did it.
Using 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
}
Here's a sample of the json :
{"Foods": [{"FoodName": "Apples","Weight": "110" } ]}
You can use Gson
.
Step 1
Add compile
compile 'com.google.code.gson:gson:2.8.2'
Step 2
Convert json to Kotlin Bean
(use JsonToKotlinClass)
Like this
Json
data
{
"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
)
}
Step 3
Use Gson
var gson = Gson()
var mMineUserEntity = gson?.fromJson(response, MineUserEntity.MineUserInfo::class.java)
This uses kotlinx.serialization
like Elisha's answer. Meanwhile the API is being stabilized for the upcoming 1.0 release. Note that e.g. JSON.parse
was renamed to Json.parse
and is now Json.decodeFromString
. Also it is imported in gradle differently starting in Kotlin 1.4.0:
dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-serialization-core:1.0.0-RC"
}
apply plugin: 'kotlinx-serialization'
Example usage:
@Serializable
data class Properties(val nid: Int, val tid: Int)
@Serializable
data class Feature(val pos: List<Double>, val properties: Properties? = null,
val count: Int? = null)
@Serializable
data class Root(val features: List<Feature>)
val root = Json.decodeFromString<Root>(jsonStr)
val rootAlt = Json.decodeFromString(Root.serializer(), jsonStr) // equivalent
val str = Json.encodeToString(root) // type 'Root' can be inferred!
// For a *top-level* list (does not apply in my case) you would use
val fList = Json.decodeFromString<List<Feature>>(jsonStr)
val fListAlt = Json.decodeFromString(ListSerializer(Feature.serializer()), jsonStr)
Kotlin's data class
defines a class that mainly holds data and has .toString()
and other methods (e.g. destructuring declarations) automatically defined. I'm using nullable (?
) types here for optional fields.
i am using my custom implementation in kotlin:
/**
* Created by Anton Kogan on 10/9/2020
*/
object JsonParser {
val TAG = "JsonParser"
/**
* parse json object
* @param objJson
* @param include - all keys, that you want to display
* @return Map<String, String>
* @throws JSONException
*/
@Throws(JSONException::class)
fun parseJson(objJson: Any?, map :HashMap<String, String>, include : Array<String>?): Map<String, String> {
// If obj is a json array
if (objJson is JSONArray) {
for (i in 0 until objJson.length()) {
parseJson(objJson[i], map, include)
}
} else if (objJson is JSONObject) {
val it: Iterator<*> = objJson.keys()
while (it.hasNext()) {
val key = it.next().toString()
// If you get an array
when (val jobject = objJson[key]) {
is JSONArray -> {
Log.e(TAG, " JSONArray: $jobject")
parseJson(
jobject, map, include
)
}
is JSONObject -> {
Log.e(TAG, " JSONObject: $jobject")
parseJson(
jobject, map, include
)
}
else -> {
//
if(include == null || include.contains(key)) // here is check for include param
{
map[key] = jobject.toString()
Log.e(TAG, " adding to map: $key $jobject")
}
}
}
}
}
return map
}
/**
* parse json object
* @param objJson
* @param include - all keys, that you want to display
* @return Map<String, String>
* @throws JSONException
*/
@Throws(JSONException::class)
fun parseJson(objJson: Any?, map :HashMap<String, String>): Map<String, String> {
return parseJson(objJson, map, null)
}
}
You can use it like:
val include= arrayOf(
"atHome",//JSONArray
"cat",
"dog",
"persons",//JSONArray
"man",
"woman"
)
JsonParser.parseJson(jsonObject, map, include)
val linearContent: LinearLayout = taskInfoFragmentBinding.infoContainer
here is some useful links:
json parsing :
plugin: https://plugins.jetbrains.com/plugin/9960-json-to-kotlin-class-jsontokotlinclass-
create POJOs from json: https://codebeautify.org/jsonviewer
Retrofit: https://square.github.io/retrofit/
A bit late, but whatever.
If you prefer parsing JSON to JavaScript-like constructs making use of Kotlin syntax, I recommend JSONKraken, of which I am the author.
Suggestions and opinions on the matter are much apreciated!
Kotlin specific library by Jetbrains for all supported platforms – Android, JVM, JavaScript, Native
https://github.com/Kotlin/kotlinx.serialization
Moshi is a JSON library for Android and Java by Square.
https://github.com/square/moshi
https://github.com/FasterXML/jackson
Most popular but almost deprecated
https://github.com/google/gson
http://www.jsonschema2pojo.org/
IntelliJ plugin - https://plugins.jetbrains.com/plugin/9960-json-to-kotlin-class-jsontokotlinclass-
There is no question that the future of parsing in Kotlin will be with kotlinx.serialization. It is part of Kotlin libraries. Version kotlinx.serialization 1.0 is finally released
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")
}
GSON is a good choice for Android and Web platform to parse JSON in a Kotlin project. This library is developed by Google. https://github.com/google/gson
1. First add GSON to your project:
dependencies {
implementation 'com.google.code.gson:gson:2.8.6'
}
2. Now you need to convert your JSON to Kotlin Data class:
Copy your JSON and go to this(https://json2kt.com) website and paste your JSON to Input Json box. Write package(ex: com.example.appName) and Class name(ex: UserData) in proper box. This site will show live preview of your data class below and also you can download all classes at once in a zip file.
After downloading all classes extract zip file & place them into your project.
3. Now Parse like below:
val myJson = """
{
"user_name": "john123",
"email": "[email protected]",
"name": "John Doe"
}
""".trimIndent()
val gson = Gson()
var mUser = gson.fromJson(myJson, UserData::class.java)
println(mUser.userName)
Done :)
Source: Stackoverflow.com