Json String from websocket to dataClass - android

I need to convert some json string that im reciving from okhttp websocket binance connection to data class to manipulate the data
override fun onMessage(webSocket: WebSocket, text: String) {
//convert string "text" to dataclass
Log.d("Websocket", text)
}
Log: D/Websocket: {"e":"24hrTicker","E":1661477897574,"s":"BNBUSDT","p":"0.30000000","P":"0.100","w":"301.82156206","x":"298.60000000","c":"298.90000000","Q":"1.06900000","b":"298.80000000","B":"353.26400000","a":"298.90000000","A":"358.58100000","o":"298.60000000","h":"307.50000000","l":"296.00000000","v":"412516.01400000","q":"124506227.71920000","O":1661391497474,"C":1661477897474,"F":581001589,"L":581229754,"n":228166}
String recived:
{
"e": "24hrTicker", // Event type
"E": 123456789, // Event time
"s": "BNBBTC", // Symbol
"p": "0.0015", // Price change
"P": "250.00", // Price change percent
"w": "0.0018", // Weighted average price
"x": "0.0009", // First trade(F)-1 price (first trade before the 24hr rolling window)
"c": "0.0025", // Last price
"Q": "10", // Last quantity
"b": "0.0024", // Best bid price
"B": "10", // Best bid quantity
"a": "0.0026", // Best ask price
"A": "100", // Best ask quantity
"o": "0.0010", // Open price
"h": "0.0025", // High price
"l": "0.0010", // Low price
"v": "10000", // Total traded base asset volume
"q": "18", // Total traded quote asset volume
"O": 0, // Statistics open time
"C": 86400000, // Statistics close time
"F": 0, // First trade ID
"L": 18150, // Last trade Id
"n": 18151 // Total number of trades
}
which is the best implementation? Thanks!

First of all,you need to have a protocol with server end, and settle down all the message IDL models.
Then you can use some tools to transfer IDL to Java Model.
as for json to model, you can use https://www.jsonschema2pojo.org/
But I suggest you use protobuf. which is more effective than json. https://square.github.io/wire/

Gson dependency
implementation 'com.google.code.gson:gson:2.9.1'
Data class of your json is like below
import com.google.gson.annotations.SerializedName
data class Websocket(
#SerializedName("e" ) var e : String? = null,
#SerializedName("E" ) var E : Int? = null,
#SerializedName("s" ) var s : String? = null,
#SerializedName("p" ) var p : String? = null,
#SerializedName("P" ) var P : String? = null,
#SerializedName("w" ) var w : String? = null,
#SerializedName("x" ) var x : String? = null,
#SerializedName("c" ) var c : String? = null,
#SerializedName("Q" ) var Q : String? = null,
#SerializedName("b" ) var b : String? = null,
#SerializedName("B" ) var B : String? = null,
#SerializedName("a" ) var a : String? = null,
#SerializedName("A" ) var A : String? = null,
#SerializedName("o" ) var o : String? = null,
#SerializedName("h" ) var h : String? = null,
#SerializedName("l" ) var l : String? = null,
#SerializedName("v" ) var v : String? = null,
#SerializedName("q" ) var q : String? = null,
#SerializedName("O" ) var O : Int? = null,
#SerializedName("C" ) var C : Int? = null,
#SerializedName("F" ) var F : Int? = null,
#SerializedName("L" ) var L : Int? = null,
#SerializedName("n" ) var n : Int? = null
)
convert your json string to data model
var gson = Gson()
val modelClassOfJsonString: Websocket = gson.fromJson("YOUR JSON STRING", Websocket::class.java)
use modelClassOfJsonString
and if you went to convert model class to json string use
var stringOfmodel : String = gson.toJson(modelClassOfJsonString)

Related

How to decode dynamic key from JSON using retrofit - Kotlin

I'm stuck decoding a dynamic value from a json file with kotlin
{
"values": {
"16694990259825982nLJ": {
"id": "16694990259825982nLJ",
"createdAt": "2022-11-26T21:43:45.982Z",
"name": "Some Text",
"owner": "xxxx#xxxx.xx",
"category": "Some Text",
"description": "Some Text.",
"template_id": "Some Text",
"last_update": "2022-11-27T00:11:51.863Z",
"users": [
"xxxx#xxxx.xx"
]
}
}
}
Here's my data class :
#Serializable
data class WorkflowsTest(
#field:SerializedName("values")
val values: Map<String, Id>
)
#Serializable
data class Id(
#field:SerializedName("owner")
val owner: String? = null,
#field:SerializedName("createdAt")
val createdAt: String? = null,
#field:SerializedName("last_update")
val lastUpdate: String? = null,
#field:SerializedName("name")
val name: String? = null,
#field:SerializedName("description")
val description: String? = null,
#field:SerializedName("template_id")
val templateId: String? = null,
#field:SerializedName("id")
val id: String? = null,
#field:SerializedName("category")
val category: String? = null,
#field:SerializedName("users")
val users: List<String?>? = null
)
This is my ApiResponse data class when fetching Data from GET HTTP URL :
#Serializable
data class ApiResponse(
#Transient
val success: Boolean? = null,
val message: String? = null,
val values: WorkflowsTest? = null,
val status: Int,
#Transient
val error: Exception? = null
)
And this is my retrofit provider network from network module
#Provides
#Singleton
fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
return Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
Logs that I get when I get the response back :
ApiResponse(success=null, message=null, **values=WorkflowsTest(values=null)**, status=1, error=null)
as you can see values are null no matter what I do, status = 1 means the request is 200 OK, success, error and message are transient and manipulated for snackbar messages.
Test on main function :
fun main() {
val jsonString = """
{
"values": {
"16694990259825982nLJ": {
"id": "16694990259825982nLJ",
"createdAt": "2022-11-26T21:43:45.982Z",
"name": "Some Text",
"owner": "xxxx#xxxx.xx",
"category": "Some Text",
"description": "Some Text.",
"template_id": "Some Text",
"last_update": "2022-11-27T00:11:51.863Z",
"users": [
"xxxx#xxxx.xx"
]
}
}
}"""
val jsonTest: WorkflowsTest =
Gson().fromJson(jsonString, WorkflowsTest::class.java)
println(jsonTest)
}
print result works fine :
WorkflowsTest(values={16694990259825982nLJ=Id(owner=xxxx#xxxx.xx, createdAt=2022-11-26T21:43:45.982Z, lastUpdate=2022-11-27T00:11:51.863Z, name=Some Text, description=Some Text., templateId=Some Text, id=16694990259825982nLJ, category=Some Text, users=[xxxx#xxxx.xx])})
> **UPDATE**
I solved the issue by only changing the Api response data class :
Old :
#Serializable
data class ApiResponse(
#Transient
val success: Boolean? = null,
val message: String? = null,
val values: WorkflowsTest? = null,
val status: Int,
#Transient
val error: Exception? = null
to the new one (focus on the values field) :
#Serializable
data class ApiResponse(
#Transient
val success: Boolean? = null,
val message: String? = null,
val values: Map<String, Id>? = null,
val status: Int,
#Transient
val error: Exception? = null
)
and magically it works.

Firebase Realtime Database has a different data key from the Kotlin data class [duplicate]

This question already has answers here:
Drop "is" prefix for Firebase Firestore fields for Boolean Values
(2 answers)
Prevent firebase from taking the method name as variable in Firebase
(2 answers)
Closed 5 months ago.
I have multiple data classes and all upload fine to Firebase Realtime database except for this one key "isCompleted" gets changed to "completed" in the database.
My data class:
data class MaintenanceLog(
val isCompleted: Boolean? = null,
val brand: String? = null,
val clientCode: String? = null,
val dateOfSubmission: Double? = null,
val details: String? = null,
val equipmentID: String? = null,
val id: String? = null,
val model: String? = null,
val name: String? = null,
val photosArray: List<String>? = null,
val refNum: String? = null,
val restaurantID: String? = null,
var hidden: Boolean? = null,
val userSelectedDate: Double? = null,
val wasFutureMaintCreated: Boolean? = null,
val workLogRef: String? = null,
val contractorCode: String? = null,
val isCalendarEvent: Boolean? = null,
val calendarEvent_venueName: String? = null,
val createdBy: String? = null
)
Implementation:
val demoLog = MaintenanceLog(
isCompleted = true,
id = "DemoLog22222",
equipmentID = "demo_equipID_123456",
refNum = "DemoRefNum_123456",
dateOfSubmission = APSDate.getCurrentDatabaseFormattedTime(),
details = "Maintenance Log created from Work Log - Demo Description",
photosArray = null,
workLogRef = "DemoRefNum_123456",
createdBy = "Demo User",
clientCode = "Demo Client",
restaurantID = "Demo Restaurant",
brand = "Demo Brand",
model = "Demo Model",
name = "Demo User",
userSelectedDate = APSDate.dateFromComponents(timeIn_Year, timeIn_Month, timeIn_Day, timeIn_Hour, timeIn_Minute),
wasFutureMaintCreated = false)
dbRef.child(FirebaseLocations.MAINTENANCE_RECORDS.code).child("111_demo_path").setValue(demoLog)
The demo log when setting the value:
And the firebase value:
Why is "isCompleted" getting changed to "completed" when uploaded to the database?

How to parse this specific json object to display driver name and lastname on my ui?

I am trying to parse the following api endpoint.
http://ergast.com/api/f1/current/driverStandings.json
I'm confused about the structure of the json response. specificaly i cant find a way to display driver's name and last name in a recycler view.
i've managed to display data from another json file of the same endpoint, but not from this one.
spent 2-3 days researching and googling.
There is a Plugin in Android Studio called JSON to Kotlin Class. You just have to copy the JSON reponse and paste it there in the plugin and it will generate the necessary classes for you, so you can visualize it more clearly. So what you would end up is:
data class ExampleJson2KtKotlin (
#SerializedName("MRData" ) var MRData : MRData? = MRData()
)
data class MRData (
#SerializedName("xmlns" ) var xmlns : String? = null,
#SerializedName("series" ) var series : String? = null,
#SerializedName("url" ) var url : String? = null,
#SerializedName("limit" ) var limit : String? = null,
#SerializedName("offset" ) var offset : String? = null,
#SerializedName("total" ) var total : String? = null,
#SerializedName("StandingsTable" ) var StandingsTable : StandingsTable? = StandingsTable()
)
data class StandingsTable (
#SerializedName("season" ) var season : String? = null,
#SerializedName("StandingsLists" ) var StandingsLists : ArrayList<StandingsLists> = arrayListOf()
)
data class StandingsLists (
#SerializedName("season" ) var season : String? = null,
#SerializedName("round" ) var round : String? = null,
#SerializedName("DriverStandings" ) var DriverStandings : ArrayList<DriverStandings> = arrayListOf()
)
data class DriverStandings (
#SerializedName("position" ) var position : String? = null,
#SerializedName("positionText" ) var positionText : String? = null,
#SerializedName("points" ) var points : String? = null,
#SerializedName("wins" ) var wins : String? = null,
#SerializedName("Driver" ) var Driver : Driver? = Driver(),
#SerializedName("Constructors" ) var Constructors : ArrayList<Constructors> = arrayListOf()
)
data class Driver (
#SerializedName("driverId" ) var driverId : String? = null,
#SerializedName("permanentNumber" ) var permanentNumber : String? = null,
#SerializedName("code" ) var code : String? = null,
#SerializedName("url" ) var url : String? = null,
#SerializedName("givenName" ) var givenName : String? = null,
#SerializedName("familyName" ) var familyName : String? = null,
#SerializedName("dateOfBirth" ) var dateOfBirth : String? = null,
#SerializedName("nationality" ) var nationality : String? = null
)
data class Constructors (
#SerializedName("constructorId" ) var constructorId : String? = null,
#SerializedName("url" ) var url : String? = null,
#SerializedName("name" ) var name : String? = null,
#SerializedName("nationality" ) var nationality : String? = null
)
And then your response will become like this if you use retrofit
interface RetrofitInterface {
#GET("example-endpoint")
suspend fun getDataList(): MRData
}
Then you just collect the data in your ViewModel and display it in the RecycleView.
The basic parsing can be achieved by this way.
val mrDataJsonObj = response.getJSONObject("MRData")
val standingTableObj = mrDataJsonObj.getJSONObject("StandingsTable")
val standingListJsonArray = standingTableObj.getJSONArray("StandingsLists")
for (i in 0 until standingListJsonArray.length()) {
val seasonObj = standingListJsonArray.get(i) as JSONObject
val driverStandingsArray = seasonObj.getJSONArray("DriverStandings")
for ( j in 0 until driverStandingsArray.length()){
val driverStandingObj = driverStandingsArray.get(j) as JSONObject
val driverObj = driverStandingObj.getJSONObject("Driver")
// Get All the Driver Attributes from driverObj
if(driverObj.has("givenName"))
Log.d(TAG, "dummyData: Given Name : " +driverObj.getString("givenName"))
if(driverObj.has("familyName"))
Log.d(TAG, "dummyData: Family Name " +driverObj.getString("familyName"))
}
}

Show JSON Data in Kotlin

I would like to place JSON Data inside the material card widget (see image). Before asking, I also did my own research - however, I can't seem to fix it. Everything that I try ends up in even more error codes.
For now, I'm just trying to get the right output by using Log. Later on, I want to place the JSON data inside the cards. However, that's a problem for later.
Hopefully providing you with enough information; this is the location of JSON file:
Code
import getJsonDataFromAsset
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
#Serializable
data class Item (
val id: Int? = null,
val image: String? = null,
val title: String? = null,
val description: String? = null,
val longDescription: String? = null,
val company: String? = null,
val price: Int? = null,
val duration: Int? = null,
val valued: String? = null
)
private var json = Json {
ignoreUnknownKeys = true
}
val jsonFileString = getJsonDataFromAsset(applicationContext, "activities.json")
val obj = json.decodeFromString<Item>(jsonFileString.toString())
if (jsonFileString != null){
Log.i("data", jsonFileString)
Log.i("obj.entertainment", obj.description.toString())
} else {
Log.e("catch", "Error")
}
Beginning of JSON-File.
I want to access the objects/properties inside the items array.
{
"items" : [
{
"id": 0,
"image": "img/glowgolf.png",
"title": "Glowgolf",
"description": "Activity description",
"longDescription": "Activity description descriptionActivity description descriptionActivity description descriptionActivity description description",
"company": "Friend",
"price": 25,
"duration": 2,
"valued": ""
}
...
Output
I/obj.entertainment: null
After trying a few more times, the following code showed the desired output.
Log.i("obj.entertainment", obj.items[0].title.toString())
Output: Glowgolf
To place it into your view add val titleActivityCard = findViewById<TextView>(R.id.titleFirstCard) and titleActivityCard.text = obj.items[0].toString()
Better answers are always welcome, but hereby the question is closed.

Firebase RealtimeDatabase retrieve snapshot object exception

This is my model class
#Parcel
data class ClientModel(
var name: String? = "",
var phone: String? = "",
var princpalAddresse: String? = "",
var homeAddresse: String? = "",
var travailleAddresse: String? = "",
var email: String? = "",
var userToken: String? = "",
var principalAddresseCoords: Pair<Double, Double>? = null,
var homeAddresseCoords: Pair<Double, Double>?= null,
var workAddresseCoords: Pair<Double, Double>? = null,
)
My proGuard file keep the class :
-keep class com.olivier.oplivre.models.ClientModel
But! when I try to get the snapshot with a singleValueEventListener I got exception because of the Pair<Double,Double> variables
val utilisationInfo = snapshot.getValue(ClientModel::class.java) //todo CRASH
Exception :
com.google.firebase.database.DatabaseException: Class kotlin.Pair does not define a no-argument constructor. If you are using ProGuard, make sure these constructors are not stripped.
Database Structure :
I think firebase Realtime database treat your principalAddresseCoords as a list of long so in your ClientModel change the value of principalAddresseCoords to emptyList() and the type List
As #Sami Shorman said , firebase took my Pair instance and transform it but not as list, as Hashmap<,> ! so I changed my class model like that :
var principalAddresseCoords: HashMap<String,Double>? = null,
var homeAddresseCoords: HashMap<String,Double >? = null,
var workAddresseCoords: HashMap<String,Double >? = null,
To put the data as Hashmap I just had to do :
clientModel.workAddresseCoords = HashMap<String,Double>().apply {
put("lat",lat)
put("long",long)
}

Categories

Resources