1

I have existing Python programs which use import json and use

json.load()  json.loads()

method to read the json and present it in code in easy to use accessible dictionary.

I use python json[name][] = value constructs to reference the json data in memory and also use the same type of syntax to assign new values to json elements.

I want to migrate the Python code to Kotlin and looking for JSON libraries which will do something close to what Python json.load() does in Kotlin.

I did use Google but did not find anything, there are plenty of Kotlin/Java JSON libraries but I dont think they offer anything like Python JSON load methods.

What is my best option library to use?

Here are Python code details, I want to do same in Kotlin and use the existing JSON libraries.

import json 
js = json.loads(response['Body'].read())

Contents of js document is this:

{
    "environment": "production",
    "postgres_host" : "pgstaging-prod.blah.blah.rds.amazonaws.com",
    "postgres_port" : 5432,
    "postgres_database" : "datawarehouse",
    "postgres_user" : "pguser",
    "postgres_password" : "!!!!!!",
    "postgres_config_schema" : "etl_operations",
    "postgres_validation_log_table_name" : "jobs_process_log",
    "postgres_destination_table_name" : "myleads",
    "debugFlag": true,
    "configBucket": "csn-datalake",
    "configFileName": "yurib_test/myleads.json",
    "HighWaterMarkFileName": "yurib_test/dts_high_watermark.json",
    "repartitionSourceTableName": "leads",
    "repartitionSourceDbName": "datalake",
    "sourceTablePartitionDateTime": "job_run_timestamp_utc",
    "repartitionTargetTableName": "outleads",
    "repartitionTargetDbName": "datalake_reports",
    "repartitionTargetS3Location": "yurib_test/outleads",
    "repartitionTargetColumnList": [
        {"colName": "message_item_countrycode", "isDatePartition": false, "renameTo" : "message_countrycode"},
        {"colName": "message_tenant_code", "isDatePartition": false, "renameTo" : "message_tenant"},
        {"colName": "message_lastupdated", "isDatePartition": true, "renameTo" : "message_lastupdated"}
        ],
    "repartitionLoadType": "incremental_data_load",
    "repartition": 4,
    "repartitionLoadTypeIncremental": "incremental_data_load",
    "repartitionLoadTypeFullInitial": "full_data_load",
    "countryCodeColName": "message_item_countrycode",
    "tenantColName": "message_tenant_code",
    "autoCreateCountryTenant": false,
    "autoCreateCountry": true,
    "autoCreateTenant": true,
    "partitionDateDefault": "0000-00-00",
    "partitionYearDefault": "0000",
    "partitionMonthDefault": "00",
    "partitionDayDefault": "00",
    "countryCodeDefault": "AU",
    "tenantDefault": "CARSALES",
    "missingPartColDataValReplace": "MISSINGDATA",
    "validateIncomingCountryTenant": true,
    "datePartitionStyle": "ym",
    "datePartitionStyleYearMonth": "ym",
    "datePartitionStyleYearMonthDay": "ymd",
    "propagateGlueJobRunGuid": false
}

here is how Python can access above json document using [] and range

    print (js["repartitionLoadType"])
    print (js['configBucket'], js['configFileName'], js['HighWaterMarkFileName'])
    print (js['repartitionTargetTableName'], js['repartitionTargetS3Location'])
    print (js['repartitionSourceTableName'], js['repartitionSourceDbName'])
    print (js['repartitionTargetDbName'], js['repartitionLoadType'])
    print (js['autoCreateCountry'], js['autoCreateTenant'], js['missingPartColDataValReplace'])
    print (js['countryCodeColName'], js['tenantColName'], js['propagateGlueJobRunGuid'])
    print (js['countryCodeDefault'], js['tenantDefault'], js['validateIncomingCountryTenant'], js['repartition'])

    partition_dts = ""
    # json array
    for i in range(0, len(js['repartitionTargetColumnList'])):
        if True == js['repartitionTargetColumnList'][i]['isDatePartition']:
            partition_dts = "`" + js['repartitionTargetColumnList'][i]['colName'] + "`"
        else:
            js['repartitionTargetColumnList'][i]['colName'] = "new value replace/assign here"
        continue

# to set/replace/assign any values above:
    js["repartitionLoadType"] = "some new value"

I hope this clarifies what I am trying to do to migrate my Python code to Kotlin.

Acid Rider
  • 1,557
  • 3
  • 17
  • 25
  • 2
    Maybe this is what you're looking for: https://stackoverflow.com/questions/44870961/how-to-map-a-json-string-to-kotlin-map – rdas Apr 13 '19 at 07:34
  • 1
    If above link doesn't cover what you need, please state what `load` offers but you didn't find something similiar on kotlin. – glee8e Apr 13 '19 at 15:32
  • 1
    you can use Gson library in kotlin – Shudipto Trafder Apr 13 '19 at 15:58
  • please see my original post - I edited the contents and provided sample python json code to see how I can do same in Kotlin using existing json libraries. Thank you. – Acid Rider Apr 13 '19 at 23:33
  • You can use below online tool to convert json to kotlin https://www.workversatile.com/json-to-kotlin-converter – Arshad Shaikh Aug 23 '22 at 18:21

1 Answers1

1

You can use Json.plain.parseJson(...) from Kotlins serialization framework to get something similar. It will create a tree of Json objects which then can be navigated like a map of maps.

import kotlinx.serialization.json.Json
import kotlinx.serialization.json.content
import java.lang.StringBuilder

fun main() {

    val js = Json.plain.parseJson(data).jsonObject

    println(js["repartitionLoadType"]?.content)
    // ...

    var partitionDts = StringBuilder()

    for (repartitionTargetColumn in js["repartitionTargetColumnList"]!!.jsonArray) {
        if (repartitionTargetColumn.jsonObject["isDatePartition"]?.primitive?.boolean!!) {
            partitionDts.append("`" + repartitionTargetColumn.jsonObject["colName"] + "`");
        }
        else {
            // JsonObjects are immutable in Kotlin
            // repartitionTargetColumn.jsonObject["colName"] = "new value replace/assign here"
        }
    }

}

Make sure to include the Kotlin serialization plugin into your project setup. See the kotlinx.serialization Github project on how to do this.

As Kotlin is a statically typed language you should probably define a data class for your Json file and parse that file into an object of this data class instead of using the untyped approach above.

import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json

@Serializable
data class BodyData(
    var environment: String,
    var repartitionLoadType: String
    // ...
)

fun main() {
    val bodyData = Json.nonstrict.parse(BodyData.serializer(), data)
    println(bodyData.repartitionLoadType)
}
Alexander Egger
  • 5,132
  • 1
  • 28
  • 42
  • re this: val bodyData = Json.nonstrict.parse(BodyData.serializer(), data) - does not compile, serializer error: Unresolved reference: serializer. But if I use the generic like so: val r = Json.nonstrict.parse(repartitionJsonConfig) // then it works. I am using latest Kotlin 1.3.31 and latest Json library as of March 2019. Thank you. – Acid Rider May 10 '19 at 05:06
  • 1
    `Unresolved reference: serializer` works with Gradle. It's a known issue with IntelliJ (strangely). `Json.nonstrict.parse(repartitionJsonConfig)` uses reflection in order to get the right serializer. This is fine for Java, but might be a problem in JS – Alexander Egger May 10 '19 at 07:26