5

I'm trying to parse Json in Kotlin. I'm having a lot of trouble, it seems that a lot of people learn Kotlin after Java... Not me, I'm a Python guy. I got a Kotlin Jupyter Notebook running fairly quickly (https://github.com/ligee/kotlin-jupyter), after that I managed to pull information from the bittrex api like so:

import java.net.URL
val result = URL("https://bittrex.com/api/v1.1/public/getmarkets").readText()

It took me a long time to find that I needed to add import java.net.URL, this always seems to be implicit in all code examples. Anyway, this give me a response in json (the "result parameter"):

{"success":true,"message":"","result":[{"MarketCurrency":"LTC","BaseCurrency":"BTC","MarketCurrencyLong":"Litecoin","BaseCurrencyLong":"Bitcoin","MinTradeSize":0.01469482,"MarketName":"BTC-LTC","IsActive":true,"Created":"2014-02-13T00:00:00","Notice":null,"IsSponsored":null,"LogoUrl":"https://bittrexblobstorage.blob.core.windows.net/public/6defbc41-582d-47a6-bb2e-d0fa88663524.png"},{"MarketCurrency":"DOGE","BaseCurrency":"BTC","MarketCurrencyLong":"Dogecoin","BaseCurrencyLong":"Bitcoin","MinTradeSize":274.72527473,"MarketName":"BTC-DOGE","IsActive":true,"Created":"2014-02-13T00:00:00","Notice":null,"IsSponsored":null,"LogoUrl":"https://bittrexblobstorage.blob.core.windows.net/public/a2b8eaee-2905-4478-a7a0-246f212c64c6.png"},{"MarketCurrency ...

Now, in Python I'd just add .json() to the "result" parameter and I can then address the json fields as a dictionary with multiple levels, like

result["success"]

Would give me:

true

Is there something like that for Kotlin? I have tried Klaxon https://github.com/cbeust/klaxon, again it took me a lot of time to realize that I have to do import com.beust.klaxon.string, it is not mentioned on the website for example, so a side question is: How do you know what you need to import when you find code examples? It seems like everybody just knows... But I digress.

My main question is: How can I address the separate fields of the Json and get them into separate variables?

Highest regards.

Freek
  • 1,097
  • 2
  • 12
  • 30
  • Re imports: By reading the api documentation or the source code, and/or simply telling the IDE to add the missing imports. Re your question, by reading the docuentation: https://github.com/cbeust/klaxon#lowLevelApi, https://github.com/cbeust/klaxon#objectBindingApi. Reading (documentation, tutorials, readmes) is an essential part of programming. – JB Nizet Jan 22 '18 at 21:08
  • Yes, I realize I have a long way to go. What you are linking to does not really tell me anything, some custom json object is constructed but the values are not read back by their respective key. There is some example code using "parser" however I get "error: unresolved reference: Parser" with no idea how to solve that (try googling that error). I feel that if could just start getting some values from that json I'm starting to get somewhere. I'm writing this after hours of searching and watching howto's. – Freek Jan 22 '18 at 21:26
  • *the values are not read back by their respective key*: yes, they are: `println("Name : ${json.string("name")}, Age : ${json.int("age")}")`. That reads the string value at the key "name", and the int value at the key "age". Re Parser: of course, again, it's a class that you need to import. – JB Nizet Jan 22 '18 at 21:32

3 Answers3

1

There are many JSON parsers out there. Your example was a Kotlin explicit one and that is not mandatory for Kotlin because there are also many basic Java parsers, which you can use just as fine in Kotlin.

For your imports. Obviously you need to import the classes you want to use and IDE's like IntelliJ handle the imports for you automatically. That means that you won't have to type any import statements, but they are added automatically when referencing those classes.

I think that nowadays some libraries just expect that you do not handle the imports yourself and thus do not assist you on finding the right imports.

My suggestion for a parser is Fuel. The library is optimized for Kotlin as well. Your problem would be solved with this simple code snippet with the help of Fuel:

"https://bittrex.com/api/v1.1/public/getmarkets".httpGet().responseJson { _, response, result ->
    if (response.responseMessage == "OK" && response.statusCode == 200) {
        val yourResult = result.get().obj().getBoolean("success")
    }
}
creativecreatorormaybenot
  • 114,516
  • 58
  • 291
  • 402
1

Something you may or may not know is that Kotlin is 100% compatible with Java, thus all the Java json parsers work well with Kotlin. I highly recommend gson. It's small (~200kb), fast, and pretty simple to use.

If this code is running in a server, jackson is pretty standard. It's the most performant json parser for java at the moment, but it's very heavy. It will take some more complicated configuration though, and I think it might require some Kotlin specific modules.

I haven't tried it yet, as it hasn't officially been released, but Kotlin offers a plugin for generating json serialization code. That will probably eventually be the standard way for Kotlin to serialize / deserialize as it should theoretically be the most performant.

spierce7
  • 14,797
  • 13
  • 65
  • 106
  • 1
    Gson is a Java library and does therefore not understand non-nullable fields of Kotlin. You will end up with null values in fields that should be non-null. It works fine otherwise. – jjoller May 21 '19 at 14:55
0

The best and quick practice is instead of manually checking for each key, generate native Kotlin "data classes" using tools e.g. https://json2kotlin.com

So your API response turns into the following couple of data classes corresponding to the JSON structure:

data class Json4Kotlin_Base (

    val success : Boolean,
    val message : String,
    val result : List<Result>
)

and

data class Result (

    val marketCurrency : String,
    val baseCurrency : String,
    val marketCurrencyLong : String,
    val baseCurrencyLong : String,
    val minTradeSize : Double,
    val marketName : String,
    val isActive : Boolean,
    val isRestricted : Boolean,
    val created : String,
    val notice : String,
    val isSponsored : String,
    val logoUrl : String
)

When you get the result, you simple map the JSON response to these data classes. The video here shows how to do it step by step.

Syed Absar
  • 2,274
  • 1
  • 26
  • 45