kotlinklaxon

Kotlin - How to read JSON string on url


I am new to Kotlin and I find library Klaxon to parse JSON. I can not find how to execute url(http://localhost:8080/items/2), read JSON string and save data to variables and print them to console. CreatedAt and UpdatedAt I do not need to save.

JSON from url:

{
    "brand": "Ferrero",
    "name": "Nutella",
    "healthy": false,
    "date": "2017-03-14T00:00:00.000Z",
    "id": 2,
    "createdAt": "2018-03-14T13:33:22.000Z",
    "updatedAt": "2018-03-20T21:23:44.000Z"
}

Code:

class DetailItem : AppCompatActivity()  {
    var itemId : String = ""
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_detail_item)
        itemId = intent.getStringExtra("itemId")
    }

    override fun onResume() {
        super.onResume()
        example()
    }

    private fun parse(name: String) : Any{
        val cls = Parser::class.java
        val inputStream = cls.getResourceAsStream(name)!!
        return Parser().parse(inputStream)!!
    }

    private fun example(){
        val url = "http://192.168.99.100:8080/items/" + itemId
        val obj = parse("url") as JsonObject

        val brand = obj.string("brand")
        val name = obj.string("name")
        println(brand + name)
    }

Solution

  • The issue is that method cls.getResourceAsStream(name) returns null, and the !! operator causes the NPE to be thrown.

    Why does cls.getResourceAsStream(name) return null? That happens because method getResourceAsStream searches for a resource (i.e., file) with the provided name among the resources you provide in your project.

    In your case, however, you want to download the JSON from a URL, so you need to first perform the download, which will give you a JSON in form of String (or something that can be converted to a String), and then parse that string with Parser().parse(yourJsonString) as JsonObject.

    EDIT

    Here's an example that uses OkHttp library:

    import com.beust.klaxon.Klaxon
    import okhttp3.Call
    import okhttp3.Callback
    import okhttp3.OkHttpClient
    import okhttp3.Request
    import okhttp3.Response
    import java.io.IOException
    
    fun main(args: Array<String>) {
        val url = "https://jsonplaceholder.typicode.com/posts/1"
    
        val client = OkHttpClient()
        val request = Request.Builder()
            .url(url)
            .build()
    
        println(Thread.currentThread())
        client.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call?, e: IOException?) {
                e?.printStackTrace()
            }
    
            override fun onResponse(call: Call?, response: Response) {
                if (!response.isSuccessful) {
                    System.err.println("Response not successful")
                    return
                }
                val json = response.body()!!.string()
                val myData = Klaxon().parse<MyData>(json)
                println("Data = $myData")
                println(Thread.currentThread())
            }
    
        })
        // Shutdown the executor as soon as the request is handled
        client.dispatcher().executorService().shutdown()
    }
    
    data class MyData(val title: String, val userId: Int)
    

    The JSON string returned by the REST API is:

    {
      "userId": 1,
      "id": 1,
      "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
      "body": "quia et suscipitsuscipit recusandae consequuntur expedita et cumreprehenderit molestiae ut ut quas totamnostrum rerum est autem sunt rem eveniet architecto"
    }
    

    That code prints:

    Thread[main,5,main]
    Data = MyData(title=sunt aut facere repellat provident occaecati excepturi optio reprehenderit, userId=1)
    Thread[OkHttp https://jsonplaceholder.typicode.com/...,5,main]
    

    Note that the onResponse callback is executed on the worker thread and not on the main one, so if you use this code in Android, you won't be able to change UI elements from there (unless you use runOnUiThread() or similar techniques)