2

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)
    }
7
  • Did you write any code so far? Here's the documentation for Klaxon Commented Mar 20, 2018 at 22:32
  • Sorry for my late answer. I added code. And error is: kotlin.KotlinNullPointerException Commented Mar 21, 2018 at 7:45
  • which line is throwing the exception? Commented Mar 21, 2018 at 8:08
  • at DetailItem.parse(val inputStream = cls.getResourceAsStream(name)!!) at DetailItem.example(val obj = parse("url") as JsonObject) at DetailItem.onResume(example()) Commented Mar 21, 2018 at 10:09
  • shouldn't parse("url") be parse(url) ? not sure if that's enough, but that seems like a problematic typo Commented Mar 21, 2018 at 10:44

2 Answers 2

1

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)

Sign up to request clarification or add additional context in comments.

5 Comments

Is there solution how to read a json on url like I posted in question? If not, how to download url and save it as json file?
Sure, you need to use an http client (or something more high level like retrofit) to call your server and retrieve the response. After that you can save it to a file or parse it directly
I post new answer to solve my problem, but it is AsyncTask, How to rewrite it and execute it only when I want?
AsyncTask is one way to do it, and to execute it when you want you do something like new MyAsyncTask().execute(...). I can provide you a more detailed answer later, in case
@misolo89 I added an example
1

I find this code to solve my problem. But it is AsyncTask, How to rewrite it and execute it only when I want?

inner class AsyncTaskHandleJson : AsyncTask<String, String, String>() {
        override fun doInBackground(vararg url: String?): String {

            var text: String
            var connection = URL(url[0]).openConnection() as HttpURLConnection
            try {
                connection.connect()
                text = connection.inputStream.use { it.reader().use { reader -> reader.readText() } }
            } finally {
                connection.disconnect()
            }

            return text
        }

        override fun onPostExecute(result: String?) {
            super.onPostExecute(result)
            handleJson(result)
        }
    }

    private fun handleJson(jsonString: String?) {

        val jsonObject = JSONObject(jsonString)

        val itemIdBrand = findViewById<TextView>(R.id.itemIdBrand)
        itemIdBrand.text = jsonObject.getString("brand")

        println(jsonObject.getString("brand"))
    }

2 Comments

what do you mean by "rewrite it" and execute it only when you want ? Meanwhile you can read this well explained documentation from google for AsyncTask object : developer.android.com/reference/android/os/AsyncTask.html
If I understand it right, AsyncTask is only executed when I call MyAsyncTask().execute(...) ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.