Iterating through JSON data - json

I am generating a JSON output in php which i need to use to fill line chart in android application writen in kotlin.
The JSON data is:
[{"reading_temperature":"14","hour":"01"},{"reading_temperature":"14","hour":"02"},{"reading_temperature":"14","hour":"03"},{"reading_temperature":"14","hour":"04"},{"reading_temperature":"14","hour":"05"},{"reading_temperature":"14","hour":"06"},{"reading_temperature":"14","hour":"07"},{"reading_temperature":"14","hour":"08"},{"reading_temperature":"14","hour":"09"},{"reading_temperature":"14","hour":"10"},{"reading_temperature":"14","hour":"11"},{"reading_temperature":"14","hour":"12"},{"reading_temperature":"14","hour":"13"},{"reading_temperature":"14","hour":"14"},{"reading_temperature":"14","hour":"15"},{"reading_temperature":"14","hour":"16"},{"reading_temperature":"14","hour":"17"},{"reading_temperature":"14","hour":"18"},{"reading_temperature":"14","hour":"19"},{"reading_temperature":"14","hour":"20"},{"reading_temperature":"14","hour":"21"},{"reading_temperature":"14","hour":"22"},{"reading_temperature":"14","hour":"23"}]
This is the part of the code where i get the JSON:
override fun doInBackground(vararg params: String?): String? {
var response:String?
try{
response = URL("https://127.0.0.1/weatherStation/temperatureDaily.php").readText(
Charsets.UTF_8
)
}catch (e: Exception){
response = null
}
return response
}
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
try {
val jsonObj = JSONObject(result)
} catch (e: Exception) {
}
}
Now i need to use that data to populate the line chart, this is hardcoded data which i need to exchange with JSON
private fun setupLineChartDataTemperatura() {
val yVals = ArrayList<Entry>()
//This next part i need to dynamically generate from JSON,
//first float value and last string value should be `"hour":"xx"`
// and second float value should be `[{"reading_temperature":"xx"`
yVals.add(Entry(0f, 4f, "0"))
yVals.add(Entry(1f, 5f, "1"))
yVals.add(Entry(1.5f, 4f, "1.5"))
yVals.add(Entry(2f, 5f, "2"))
yVals.add(Entry(3f, 3f, "3"))
yVals.add(Entry(4f, 2f, "4"))
val set1: LineDataSet
set1 = LineDataSet(yVals, "Temperatura")
val dataSets = ArrayList<ILineDataSet>()
dataSets.add(set1)
val data = LineData(dataSets)
chart1.setData(data)
chart1.description.isEnabled = false
chart1.legend.isEnabled = true
chart1.setPinchZoom(false)
chart1.xAxis.enableGridDashedLine(5f, 5f, 0f)
chart1.axisRight.enableGridDashedLine(5f, 5f, 0f)
chart1.axisLeft.enableGridDashedLine(5f, 5f, 0f)
chart1.setDrawGridBackground(true)
chart1.xAxis.labelCount = 11
chart1.xAxis.position = XAxis.XAxisPosition.BOTTOM
chart1.setTouchEnabled(true)
chart1.invalidate()
}

I have managed to do it:
val jsonTemperatureData = JSONArray(result)
for (i in 0 until jsonTemperatureData.length()) {
val item = jsonTemperatureData.getJSONObject(i)
val reading_temperature = item.getString("reading_temperature")
val hour = item.getString("hour")
yVals.add(Entry(hour.toFloat(), reading_temperature.toFloat(), hour.toString()))
}

Related

Nested JSON Objects in Kotlin with Volley

I am very new to this as you can probably tell, but i'm trying to parse a JSON url with Volley using Kotlin in Android Studio. The url contains nested Objects, not nested Arrays.
I can display everything inside "questionnaire", but I only want to display "typeOfQuestion". How do i do that?
MainActivity.kt:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
questionTV = findViewById(R.id.idTVQuestion)
answerTV = findViewById(R.id.idTVAnswer)
typeTV = findViewById(R.id.idTVType)
val queue: RequestQueue = Volley.newRequestQueue(applicationContext)
val request = JsonObjectRequest(Request.Method.GET, url, null, { response ->
loadingPB.setVisibility(View.GONE)
try {
val question: String = response.getString("question")
val answer: String = response.getString("answer")
val typeOfQuestion: String = response.getString("typeOfQuestion")
questionTV.text = question
answerTV.text = answer
typeTV.text = typeOfQuestion
} catch (e: Exception) {
e.printStackTrace()
}
}, { error ->
Log.e("TAG", "RESPONSE IS $error")
Toast.makeText(this#MainActivity, "Fail to get response", Toast.LENGTH_SHORT)
.show()
})
queue.add(request)
}
}
Heres the JSON:
{
"questionnaire": {
"question": "Where do you live?",
"answer": "In the mountains",
"typeOfQuestion": "Informative
}
}
You have object inside another json object.If you need to access field from child object you need to get child jsonObject and then get fields from object.
var questionnaire = response.getJSONObject("questionnaire")
You need to get fields from questionnaire object.Like.
val question: String = questionnaire.getString("question")
val answer: String = questionnaire.getString("answer")
val typeOfQuestion: String = questionnaire.getString("typeOfQuestion")

How do I de-serialize this json?

I am working on a project where I need to access currency rates once a day so I am trying to use this json.
To read this, I am simply getting the text of the URL and then trying to use the JSONReader to de-serialize.
val url = URL("https://www.floatrates.com/daily/usd.json")
val stream = url.openStream()
url.readText()
val jsonReader = JsonReader(InputStreamReader(stream))
jsonReader.isLenient = true
jsonReader.beginObject()
while (jsonReader.hasNext()) {
val codeName:String = jsonReader.nextName()
jsonReader.beginObject();
var code:String? = null
var rate = 0.0
while (jsonReader.hasNext()) {
val name:String = jsonReader.nextName()
when(name){
"code" -> {
code = jsonReader.nextString()
break
}
"rate" -> {
rate = jsonReader.nextDouble()
break
}
else -> {
jsonReader.skipValue()
}
}
code?.let {
rates?.set(it, rate)
}
}
}
jsonReader.endObject();
When I run the code , I get:
Expected BEGIN_OBJECT but was STRING
at
jsonReader.beginObject();
When I try using Gson, with the code below:
var url = URL("https://www.floatrates.com/daily/usd.json").readText()
//url = "[${url.substring(1, url.length - 1)}]"
val gson = Gson()
val currencies:Array<SpesaCurrency> = gson.fromJson(url, Array<SpesaCurrency>::class.java)
I get this error :
Expected BEGIN_OBJECT but was STRING at line 1 column 3 path $[0]
at:
gson.fromJson(url, Array<SpesaCurrency>::class.java)
SpesaCurrency.kt looks like this:
class SpesaCurrency(
val code:String,
val alphaCode:String,
val numericCode:String,
val name:String,
val rate:Float,
val date:String,
val inverseRate:Float
)
Any help is greatly appreciated.
I think there is one
jsonReader.endObject();
missing in your code. That imbalance causes the program to fail after the first object has been read. Add it after the inner
while (jsonReader.hasNext()) {
...
}
loop.

Post Request in Kotlin

I'm trying to do a post request in Android Studio written in Kotlin
I'm posting a JSON object to our server and then the server is returning a JSON object back. But what I'm doing here is decoding the response body as a string and then converting it into the data structure we need. I'm sure there is a better and simpler way to do what I need done.
My current code works but the major issue I'm having is formatting the string if our objects have nested objects which is why I want to figure out a better way to turn the response body into a json object.
I'm not too familiar with many request libraries for kotlin but I have looked into okhttp3 but I'm not sure how to post a json object, attach headers and decode the response body into a json object.
I know for okhttp3 I need to convert the json object to a string to post other than that I'm lost.
Breakdown of what's needed:
Post JSON Object To Server
Send Headers With Post Request
Decode Response Body into JSON Object/ Kotlin Equivalent
Simplify What I'm Trying to Do if Possible
This is the current code I have
private fun postRequestToGetDashboardData() {
val r = JSONObject()
r.put("uid", muid)
r.put("token", mtoken)
SendJsonDataToServer().execute(r.toString());
}
inner class SendJsonDataToServer :
AsyncTask<String?, String?, String?>() {
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
if (result.equals(null)) {
val t = Toast.makeText(this#Home, "No devices to display", Toast.LENGTH_LONG)
t.setGravity(Gravity.CENTER, 0, 0)
t.show()
} else {
intentForUnique.putExtra("FirstEndpointData", result)
var list = handleJson(result)
adapter.submitList(list)
dashboardItem_list.adapter = adapter
adapter.notifyDataSetChanged();
dashboardItem_list.smoothScrollToPosition(0);
}
}
override fun doInBackground(vararg params: String?): String? {
val JsonDATA = params[0]!!
var urlConnection: HttpURLConnection? = null
var reader: BufferedReader? = null
try {
val url = URL("URL");
urlConnection = url.openConnection() as HttpURLConnection;
urlConnection.setDoOutput(true);
urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("Content-Type", "application/json");
urlConnection.setRequestProperty("Authorization", mtoken);
urlConnection.setRequestProperty("Accept", "application/json");
val writer: Writer =
BufferedWriter(OutputStreamWriter(urlConnection.getOutputStream(), "UTF-8"));
writer.write(JsonDATA);
writer.close();
val inputStream: InputStream = urlConnection.getInputStream();
if (inputStream == null) {
return null;
}
reader = BufferedReader(InputStreamReader(inputStream))
var inputLine: String? = reader.readLine()
if (inputLine.equals("null")) {
return null
} else {
return inputLine
}
} catch (ex: Exception) {
Log.e(TAG, "Connection Failed", ex);
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (ex: Exception) {
Log.e(TAG, "Error closing stream", ex);
}
}
}
return null
}
}
private fun handleJson(jsonString: String?): ArrayList<SensorData> {
val jsonArray = JSONArray(jsonString)
val list = ArrayList<SensorData>()
var x = 0
while (x < jsonArray.length()) {
val jsonObject = jsonArray.getJSONObject(x)
list.add(
SensorData(
jsonObject.getInt("deviceId"),
// jsonObject.getString("deviceName"),
jsonObject.getInt("battery"),
jsonObject.getString("dateTime"),
jsonObject.getInt("airValue"),
jsonObject.getInt("waterValue"),
jsonObject.getInt("soilMoistureValue"),
jsonObject.getInt("soilMoisturePercent")
)
)
x++
}
return list
}
So the json data being returned back is an array of this structure (our backend is written in Go)
type Device struct {
DeviceID int `bson:"deviceId" json:"deviceId"`
Battery int `bson:"battery" json:"battery"`
DateTime time.Time `bson:"dateTime" json:"dateTime"`
AirValue int `bson:"airValue" json:"airValue"`
WaterValue int `bson:"waterValue" json:"waterValue"`
SoilMoistureValue int `bson:"soilMoistureValue" json:"soilMoistureValue"`
SoilMoisturePercent int `bson:"soilMoisturePercent" json:"soilMoisturePercent"`
}

How to add Body request in url in Kotlin?

Here is my Code that for Volley Request:-
val searchRequest = object : JsonArrayRequest(Request.Method.GET,url,
Response.Listener { response ->
val result = response.toString()
},
Response.ErrorListener { error ->
Toast.makeText(activity, "Error!",Toast.LENGTH_LONG)
.show()
Log.d("ERROR",error.toString())
})
{
override fun getBody(): ByteArray {
// TODO add Body, Header section works //////////
return super.getBody()
}
override fun getBodyContentType(): String {
return "application/json"
}
override fun getHeaders() : Map<String,String> {
val params: MutableMap<String, String> = HashMap()
params["Search-String"] = songName
params["Authorization"] = "Bearer ${accessTx.text}"
return params
}
}
AppController.instance!!.addToRequestQueue(searchRequest)
I want to add this information in the body section
video_id = "BDJIAH" , audio_quality = "256"
here is the sample to add above information in the below segment.
{ "video_id":"ABCDE", "audio_quality":"256" }
Basically, I am facing problem in ByteArray section. That doesn't work for me.
You can use toByteArray() method of String class in Kotlin.
For example:
val charset = Charsets.UTF_8
val byteArray = "SomeValue".toByteArray(charset)
Also try to pass multiple values in the request body in this way:
val requestBody = "video_id = "+"ABCDE"+ "& audio_quality ="+ "256"
val charset = Charsets.UTF_8
val byteArray = requestBody.toByteArray(charset)

Scala : Retry with try/catch for exception handling

I am trying to add a retry logic for JSON conversion. When converting an object to json, I am retrying for 3 times if there is any exception. I am doing :
var mapper = new ObjectMapper() with ScalaObjectMapper
intializeMapper( )
def intializeMapper() = {
// jackson library does not support seralization and deserialization of
// of scala classes like List and Map, this is needed to support it
mapper.registerModule( DefaultScalaModule )
// enables parsing of NaN. Enabling it here as JsonUtil class currently in
// use supports it.
mapper.configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true )
mapper.setSerializationInclusion(Include.NON_NULL)
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
}
def getPersonRDD(result: DataFrame): RDD[(String, String)] = {
val finalValue = result.rdd.map({
r =>
val customerId = r.getAs[String](CUSTOMER_ID)
val itemId = r.getAs[Map[String, Int]](ITEM_ID)
val itemName = r.getAs[Map[String, Int]](ITEM_NAME)
val person = Person(itemId, itemName)
val jsonString = toJson(person)
(customerId, jsonString)
})
return finalValue
}
def fromJson(json: String, clazz: Class[_]) = {
mapper.readValue(json, clazz)
}
def toJson(value: Any): String = {
var jsonString: String = " "
jsonString = mapper.writeValueAsString(value)
try {
fromJson(jsonString, clazz)
return jsonString
} catch {
case Exception => {
publishMetrics(PARSING_EXCEPTION, 1.0)
val result = util.Try(retry() {
jsonString = mapper.writeValueAsString(value)
val features = fromJson(jsonString, clazz)
})
result match {
case util.Success(value) => jsonString
case util.Failure(error) => {
log.error("Error while parsing JSON " + jsonString)
return jsonString
}
}
}
}
}
// Returning T, throwing the exception on failure
#annotation.tailrec
def retry[T](n: Int = 3)(fn: => T): T = {
util.Try {
fn
} match {
case util.Success(x) => x
case _ if n > 1 => retry(n - 1)(fn)
case util.Failure(e) => throw e
}
}
case class Person(itemId: Map[String, Int], itemName: Map[String, Int]) extends Serializable
Is this correct ? I am new to Scala. Can someone suggest me if there is any better way for achieving this ? Is there predefined retry logic available in Scala ? The reason I am trying to add retry logic for JSON conversion is due to Jackson version I use(which I can't change for now), sometimes my writeValueAsString results in incomplete JSON.
You retry function seems correct. The only flaw I can think of is that if you expect something would fail it's better just make the return type Try[T], so you can handle it outside in the scala way.
Here is one of my implementation:
def retry[T](n: Int)(block: => T): Try[T] = {
val stream = Stream.fill(n)(Try(block))
stream find (_.isSuccess) getOrElse stream.head
}