json data parsing using retrofit and rxjava2 data display in Textview and TableLayout - json
JSON Data Parsing Using Retofit2 and Rxjava2. This Data get In ArrayList successfully. its ArrayList Size is Nine but its display only two Record in Table. After Two Record its Kotlin.NullPointerException.
JSON Data:
{"success":1,"salesGst":[{"Cmp_Name":"ABC","GSTIN":"AAAA","FirmName":"SALES GJ","ChallanNo":"1","ChallanDate":"2019-03-15 00:00:00","ChallanAmount":"2778.75","TaxTotal":"2778.75","InvoiceType":"Retail Invoice","CGSTTotal":"0.0","PartyGST":"CDE","SGSTTotal":"0.0","IGSTTotal":"0.0"},{"Cmp_Name":"ABC","GSTIN":"AAAA","FirmName":"SALES GJ","ChallanNo":"1","ChallanDate":"2019-03-13 00:00:00","ChallanAmount":"2203.0","TaxTotal":"2118.5","InvoiceType":"Tax Invoice","CGSTTotal":"52.96","PartyGST":"CDE","SGSTTotal":"52.96","IGSTTotal":"0.0"},{"Cmp_Name":"ABC","GSTIN":"AAAA","FirmName":"VIKAS","ChallanNo":"2","ChallanDate":"2019-03-16 00:00:00","ChallanAmount":"6975.0","TaxTotal":"6975.0","InvoiceType":"Retail Invoice","CGSTTotal":"0.0","PartyGST":null,"SGSTTotal":"0.0","IGSTTotal":"0.0"},{"Cmp_Name":"ABC","GSTIN":"AAAA","FirmName":"SALES MH","ChallanNo":"2","ChallanDate":"2019-03-13 00:00:00","ChallanAmount":"420.0","TaxTotal":"403.75","InvoiceType":"Tax Invoice","CGSTTotal":"0.0","PartyGST":"ABC","SGSTTotal":"0.0","IGSTTotal":"20.19"},{"Cmp_Name":"ABC","GSTIN":"AAAA","FirmName":"SALES GJ","ChallanNo":"3","ChallanDate":"2019-03-14 00:00:00","ChallanAmount":"4788.0","TaxTotal":"4560.0","InvoiceType":"Tax Invoice","CGSTTotal":"114.0","PartyGST":"CDE","SGSTTotal":"114.0","IGSTTotal":"0.0"},{"Cmp_Name":"ABC","GSTIN":"AAAA","FirmName":"SALES GJ","ChallanNo":"4","ChallanDate":"2019-03-15 00:00:00","ChallanAmount":"241.9","TaxTotal":"230.38","InvoiceType":"Tax Invoice","CGSTTotal":"5.76","PartyGST":"CDE","SGSTTotal":"5.76","IGSTTotal":"0.0"},{"Cmp_Name":"ABC","GSTIN":"AAAA","FirmName":"SALES GJ","ChallanNo":"5","ChallanDate":"2019-03-15 00:00:00","ChallanAmount":"5563.68","TaxTotal":"5101.5","InvoiceType":"Tax Invoice","CGSTTotal":"231.28","PartyGST":"CDE","SGSTTotal":"231.28","IGSTTotal":"0.0"},{"Cmp_Name":"ABC","GSTIN":"AAAA","FirmName":"SALES GJ","ChallanNo":"6","ChallanDate":"2019-03-16 00:00:00","ChallanAmount":"13238.0","TaxTotal":"12459.25","InvoiceType":"Tax Invoice","CGSTTotal":"389.29","PartyGST":"CDE","SGSTTotal":"389.29","IGSTTotal":"0.0"},{"Cmp_Name":"ABC","GSTIN":"AAAA","FirmName":"SALES MH","ChallanNo":"7","ChallanDate":"2019-03-16 00:00:00","ChallanAmount":"2074.0","TaxTotal":"1975.0","InvoiceType":"Tax Invoice","CGSTTotal":"0.0","PartyGST":"ABC","SGSTTotal":"0.0","IGSTTotal":"98.75"}]}
Please Guide Me,After Getting How to Show in TableLayout.
In ArrayList Nine Record but in Table show only Two Record another seven record is not display. in third record taxtotal give kotlin.nullpointerException. what missing?
private fun displaySalesGSTData(salesGSt : List<SalesGST>) {
salesGST = SalesGST()
tvSalesCompanyName.setText(salesGSt.get(1).Cmp_Name)
tvGSTIN.setText(salesGSt.get(1).GSTIN)
val rowHeader = TableRow(this#Sales)
rowHeader.setBackgroundColor(Color.parseColor("#c0c0c0"))
rowHeader.setLayoutParams(TableLayout.LayoutParams(TableLayout.LayoutParams.MATCH_PARENT,
TableLayout.LayoutParams.WRAP_CONTENT))
val headerText = arrayOf<String>("Sr.No.", "Invoice Type", "Bill No.", "Bill Date", "Firm Name", "GST NO","TAX Total","CGST","SGST","IGST","Net Amount")
for (c in headerText)
{
val tv = TextView(this#Sales)
tv.setLayoutParams(TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT,
TableRow.LayoutParams.WRAP_CONTENT))
tv.setGravity(Gravity.CENTER)
// tv.setBackgroundResource(R.drawable.table_header)
tv.setTextColor(Color.parseColor("#3F51B5"))
tv.setTextSize(18F)
tv.setPadding(5, 5, 5, 5)
tv.setText(c)
rowHeader.addView(tv)
}
tableMarks.addView(rowHeader)
for (j in 0 until salesGSt.size)
{
/*val jsonObject1 = jsonArray.getJSONObject(j)
val date = jsonObject1.getString("ExamDate")
val inputFormatter1 = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
val date1 = inputFormatter1.parse(date)
val outputFormatter1 = SimpleDateFormat("dd-MMM-yyyy")
ExamDate = outputFormatter1.format(date1)*/
/* String replaceDate = date.replace("/Date(", "").replace(")/", "");
Long getDate = Long.valueOf(replaceDate);
ExamDate = dateFormat.format(getDate);*/
/*Subject = jsonObject1.getString("subject")
ExamName = jsonObject1.getString("ExamName")
TotalMark = jsonObject1.getLong("TotalMarks")
PassingMark = jsonObject1.getLong("PassingMarks")
Mark = jsonObject1.getLong("Marks")*/
var fName : String = salesGSt.get(j).FirmName!!
var invoice : String = salesGSt.get(j).InvoiceType!!
var bill_no : String = salesGSt.get(j).ChallanNo!!
var bill_date : String = salesGSt.get(j).ChallanDate!!
var gst_no : String = salesGSt.get(j).PartyGST!!
var tax_total : Double = salesGSt.get(j).TaxTotal!!.toDouble()
var cgst : String = salesGSt.get(j).CGSTTotal!!
var igst : String = salesGSt.get(j).IGSTTotal!!
var sgst : String = salesGSt.get(j).SGSTTotal!!
var net_amount : String = salesGSt.get(j).ChallanAmount!!
var sr : Int = j + 1
// dara rows
val row = TableRow(this#Sales)
row.setLayoutParams(TableLayout.LayoutParams(TableLayout.LayoutParams.MATCH_PARENT,
TableLayout.LayoutParams.WRAP_CONTENT))
val colText = arrayOf<String>(sr.toString(),(invoice), bill_no, bill_date, fName, gst_no, tax_total.toString(),cgst,sgst,igst,net_amount)
for (text in colText)
{
val tv = TextView(this#Sales)
tv.setLayoutParams(TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT,
TableRow.LayoutParams.WRAP_CONTENT))
tv.setGravity(Gravity.CENTER)
// tv.setBackgroundResource(R.drawable.table_shape)
tv.setTextSize(18F)
tv.setTextColor(Color.parseColor("#3F51B5"))
tv.setPadding(5, 5, 5, 5)
tv.setText(text)
row.addView(tv)
}
tableMarks.addView(row)
}
}
The 3rd item, salesGst[2], is "PartyGST": null. Your json deserializer library won't handle non-null fields as it's written in Java. I assume you have a data class where PartGST is defined as non-null, yet the deserializer will still parse it as null. Therefore, when you access PartyGST then you will receive a NullPointerException because Kotlin is expecting it to be non-null. This is a good article, which explains in more detail:
I've trusted you! You promised no null pointer exceptions!
A solution to this would be to have two models. The DTO (for JSON response) where all fields are optional and your internal model (used by your app), where you define which fields you want to be optional. Then you can have a mapper to handle the case where a field is null in the DTO, but non-null in your internal model:
// Models for your API response
data class SalesGstsDTO(val gsts: List<GstDTO>)
data class GstDTO(val name: String?, val surname: String?)
// Internal models used by your app
data class SalesGsts(val gsts: List<Gst>)
data class Gst(val name: String, val surname: String?)
class SalesGstDTOMapper {
fun mapToSalesGsts(salesGstsDTO: SalesGstsDTO): SalesGsts {
val gsts = mutableListOf<Gst>()
salesGstsDTO.gsts.map {
val name = it.name ?: return#map // Skips this item. You could handle this how you wish
val surname = it.surname
val gst = Gst(name, surname)
gsts.add(gst)
}
return SalesGsts(gsts)
}
}
This also allows you to decouple your app from the JSON response.
Related
How to convert data class to map
I tried convert to data class to map. (Under the code is just example code) data class User ( val name : String = "", val age : Int = 0, val deviceGroup: MutableSet<DeviceGroup> = mutableSetOf() ) data class DeviceGroup ( val name : String = "", val deviceLink : MutableSet<DeviceLink> = mutableSetOf() ) data class DeviceLink ( val id : Int = 0, val device : Device ) data class Device ( val devId : Int = 0, val name : String = "" ) fun main (request : HttpServletRequest) { val currentUser = request.session.getAttribute("user") as User val data = userRepository.findByName(currentUser.name) // return currentUser // result is {name="test", age=17, deviceGroup = [{name="group1"}, {name="group2"}]} // I want deserialization data class to Map val response = data.deviceGroup.toMap() response.deivceGroup.forEach { // And add new key, pair it.add(Map<String, MutableSet<Device>>("devices", mutableSetOf())) // Lastly, I want put in the value deviceGroupRepository.findByName(it.name).deviceLink.forEach { it.devices.add(this) } } return response } if just return the data value, that's result is "{name="test", age=17, deviceGroup = [{name="group1"}, {name="group2"}]}" How to convert to data class to Map object and add new key pair?
Use associate to turn a collection into a Map The Kotlin standard library provides a function called associate which will take a collection of objects and transform them into a map. It takes one argument, which is a function specifying what the keys and values of the map should be. For example, in your case, you would call it like this: val response = data.deviceGroup.associate { it.name to it.deviceLink } It will return a Map<String, MutableSet<DeviceLink>> where the key is the name of the device group and the value is the deviceLink set. The easiest way to add new values is simply to append them with the + operator. val response = data.deviceGroup.associate { it.name to it.deviceLink } + mapOf("device" to emptySet()) If you need more control than that, you could use .toMutableMap() so new entries can be added using put. val response = data.deviceGroup.associate { it.name to it.deviceLink }.toMutableMap() response.put("device", emptySet())
Pass DataType of the Class
I have the following data class, which stores two values, JSON and dataType: data class DataTypeItem( var json : String = "", var dataType : Class<*> ?= null ) I have the list defined in the following way: val dataTypeList = mutableMapOf<String, DataTypeItem>() dataTypeList.put( "item_1", DataTypeItem( json1, MyDataType::class.java ) ) dataTypeList.put( "item_2", DataTypeItem( json1, List<MyDataType>::class.java ) ) Please note that in one case I'm using the MyDataType as the DataType and in the other List < MyDataType >. Now I would like to loop through each of the dataTypeList items and parse JSON for the given data type into it's model: fun init() { dataTypeList.forEach { dataTypeItem -> val model = Gson().fromJson( dataTypeItem.value.json, dataTypeItem.value.dataType::class.java ) } } I'm using the following model: data class dataTypeItem( #SerializedName("sqlId") val sqlId: String, #SerializedName("name") val name: String ) But I keep getting an Runtime exception: Attempted to deserialize a java.lang.Class. Forgot to register a type adapter? In addition, in case it's a list, I need to call toList() on Gson().fromJSON(..): fun init() { dataTypeList.forEach { dataTypeItem -> val model; if( dataTypeItem.value.dataType::class.java is Array ) model = Gson().fromJson( dataTypeItem.value.json, dataTypeItem.value.dataType::class.java ).toList() else model = Gson().fromJson( dataTypeItem.value.json, dataTypeItem.value.dataType::class.java ) } } How can I pass the dataType dynamically and distinguish if it's a List/Array or straight up class? In addition, whenever I try to call toList(), I get an error that it's undefined. If I specify the class directly, then it's working fine var model = Gson().fromJson( json, DataTypeItem::class.java ) or var model = Gson().fromJson( json, Array<DataTypeItem>::class.java ) but I need to be able to specify it dynamically as an argument
This code works fine: val dataTypeMap = mapOf( "item_1" to MyDataTypeItem("""{"sqlId" : "1", "name" : "a"}""", MyDataType::class.java), "item_2" to MyDataTypeItem("""[{"sqlId" : "1", "name" : "a"}, {"sqlId" : "2", "name" : "b"}]""", Array<MyDataType>::class.java) ) val result = dataTypeMap.map{ Gson().fromJson(it.value.json, it.value.dataType) } I renamed DataTypeItem to MyDataTypeItem and dataTypeItem to MyDataType. Why you need to call toList()? If it is really necessary you can do the following instead: val result = dataTypeMap.map { if (it.value.dataType?.isArray == true) Gson().fromJson<Array<*>>(it.value.json, it.value.dataType).toList() else Gson().fromJson(it.value.json, it.value.dataType) }
JsonResult is sending Json parsed object as empty array collection to browser [[]],[[]]
I'm trying to add to the JsonResult object a parsed Json string, but I couldn't do it, the parser object in the browser is shown as: "filter":[[[]],[[[],[]]]] This is the full code public JsonResult AjaxStandardGet(int id) { Standard ec = db.Standard.FirstOrDefault(s => s.IdStandard == id); // inside filter: { "KeyDynamic1": "Value1", "KeyDynamic2": [ "AAA", "DDD"] } var filter = JsonConvert.DeserializeObject(ec.Filter); return Json(new { ec.IdStandard, ec.Description, filter, ec.Observations, Services = ec.StandardServices.Select(s => new { s.IdStandardServices, Tecnology = s.Tecnology?.Nombre, ServiceType = s.ServiceType?.Description, s.Quantity, s.Cost, Options = (!string.IsNullOrEmpty(s.Options) ? s.Options.Split(',') : null), Total = s.Quantity * s.Cost }), Success = true }); } I can't create the model object because the filters are not allways the same. I tried this: Dictionary<string, object> filter = JsonConvert.DeserializeObject<Dictionary<string, object>>(ec.Filter); And I get "filter":{"KeyDynamic1":"Value1","KeyDynamic2":[[],[]]}
I suggest you to JToken or dynamic: JToken filter = JToken.Parse(ec.Filter); dynamic filter = JsonConvert.DeserializeObject<dynamic>(ec.Filter); Here is working fiddle. Update It seems that JavaScriptSerializer is not able to do it. So you can serialize your result using Newtonsoft.Json and return it as a string: var result = new { ec.IdStandard, ec.Description, filter, ec.Observations, Services = ec.StandardServices.Select(s => new { s.IdStandardServices, Tecnology = s.Tecnology?.Nombre, ServiceType = s.ServiceType?.Description, s.Quantity, s.Cost, Options = (!string.IsNullOrEmpty(s.Options) ? s.Options.Split(',') : null), Total = s.Quantity * s.Cost }), Success = true }; var json = JsonConvert.SerializeObject(result); return Content(json, "application/json");
remove duplicate entries while executing repeated job to save json data in mongo
I am having following structure currently present in my database, i am executing a service to fetch data from REST api and storing it to my database , so that i can use it to display it frequently on UI as like caching a data db.countDetails.find().pretty() { "_id" : ObjectId("5670xxxx"), "totalProjectCount" : 53, "activeProjectCount" : 29, "completedProjectCount" : 1, "userCount" : 85 } { "_id" : ObjectId("5670ea97f14c717a903e8423"), "totalProjectCount" : 48, "activeProjectCount" : 41, "completedProjectCount" : 0, "userCount" : 123 } My collection is going to remain same only values will be going to change, so please suggest me a way in which i can place the updated values in mongo and at the same time i can fetch data on my UI my new values might be like db.countDetails.find().pretty() { "_id" : ObjectId("5670xxxx"), "totalProjectCount" : 23, "activeProjectCount" : 17, "completedProjectCount" : 1, "userCount" : 60 } { "_id" : ObjectId("5670ea97f14c717a903e8423"), "totalProjectCount" : 45, "activeProjectCount" : 40, "completedProjectCount" : 0, "userCount" : 113 } function to fetch data from REST api def getCount(String companyName, String apiKey) { //declaration section List returnList = [] int totalProjectCount = 0 //variable to hold total no of projects value int activeProjectCount = 0 //variable to hold total active projects value int completedProjectCount = 0 //variable to hold total completed projects value int userCount = 0 //variable to hold total active user count String userAPIKey = apiKey //user API key for authorization String method = 'GET' //method of request String totalProjectURL = "https://"+ companyName + ".teamwork.com/projects.json?status=ALL" // Url to access All projects StringBuilder out = getConnection(totalProjectURL, method, userAPIKey) //String builder to hold result //catching result into json JSONObject object = new JSONObject(out.toString()) //JSON object to store String in json format totalProjectCount = object.projects.length() String activeProjectCountURL = "https://"+ companyName + ".teamwork.com/projects.json?status=ACTIVE" // Url to access Active projects out = getConnection(activeProjectCountURL, method, userAPIKey) //catching result into json object = new JSONObject(out.toString()) activeProjectCount = object.projects.length() String completedProjectCountURL = "https://"+ companyName + ".teamwork.com/projects.json?status=COMPLETED" // Url to access completed projects out = getConnection(completedProjectCountURL, method, userAPIKey) //catching result into json object = new JSONObject(out.toString()) completedProjectCount = object.projects.length() String peopleURL = "https://"+ companyName + ".teamwork.com/people.json" // Url to access total active users out = getConnection(peopleURL, method, userAPIKey) //catching result into json object = new JSONObject(out.toString()) userCount = object.people.length() Map returnMap = [:] returnMap.put('totalProjectCount', totalProjectCount) returnMap.put('activeProjectCount', activeProjectCount) returnMap.put('completedProjectCount', completedProjectCount) returnMap.put('userCount', userCount) addCount(returnMap, 'curo', 'countDetails') println('project count successfully saved.') } function to add countDetails to mongo def addCount(Map userMap, String dbName, String collectionName) { try { DB db = mongo.getDB(dbName) DBCollection table = db.getCollection(collectionName) table.insert(userMap as BasicDBObject) def srvcResponseObj = [ responseStatus : "pass", responseCode : 200 ] return srvcResponseObj } catch (Exception e) { println "Exception related to Mongo add record" e.printStackTrace() def srvcResponseObj = [ responseStatus : "fail", responseCode: 400 ] return srvcResponseObj } } function to fetch data from mongo def fetchCountDetails(String databaseName, String collectionName) { println 'inside fetch count details' try { DB db = mongo.getDB(databaseName) DBCollection table = db.getCollection(collectionName) DBCursor cursor = table.find() Map returnCountMap = [:] List temp = [] int cursorCounter = 0 while(cursor.hasNext()) { Map temporaryMap = [:] BasicDBObject doc = (BasicDBObject) cursor.next() doc.remove('_id') temp.add(doc) cursorCounter++ } returnCountMap.put('totalProjectCount', temp.totalProjectCount.sum()) returnCountMap.put('activeProjectCount',temp.activeProjectCount.sum()) returnCountMap.put('completedProjectCount',temp.completedProjectCount.sum()) returnCountMap.put('userCount',temp.userCount.sum()) if(cursorCounter>1) println "Multiple objects found for eventID" if(cursorCounter==0) println "No objects found for eventID" return returnCountMap } catch (Exception e) { println "Exception related to Mongo >> fetchUserDetails" e.printStackTrace() def srvcResponseObj = [ responseStatus : "fail", responseCode: 400 ] return srvcResponseObj } } now i am making request to REST api after fixed amount of interval and my response gets changed in terms of values, but if i call the add function again and again my documents get duplicated in mongodb and my expected result is that my new values gets reflected in mongodb
Create Object from JSON with id predefined in Grails
I have a problem! need to get a json object that already with an id already set that is not yet saved. but when trying to create the object id is null. And it is only set when call the save method generating different id's. ex: objetoJson = {id: "123413215123", name: "Leonan Teixeira", address: {id: "12345", city: "Victory", state: "Bahia"}} def person = new Person (objetoJson) end state of the object: Person.id = null Person.Address = null but I need the id are stored. the same happens if I do person.properties = objetoJson My classes are mapped with id 'uuid' String id; static mapping = { id generator: 'uuid' } Solution add a bindable:true to the constraints class MyDomain { static constraints = { // allow binding of "id" attribute (e.g. in constructor or url parameters) id bindable: true } } http://www.redcube.de/assigning-id-domain-objects-grails-via-constructor/
Try this: def jsonSlurper = new JsonSlurper() def dataPerson = jsonSlurper.parseText('{ "id":"123456789", "nome": "Leonardo Meurer", "age":"29" }') def person = new Person (dataPerson)