Gson Pojo class - android

I'm making cryptocurrency information viewer now. I use Retrofit to get response, but have some problem.
https://api.coinone.co.kr/ticker/?currency=all
This is the api I use. and its structure is... too complicated to make pojo class.
if I make convert this to pojo class, then pojo class will be like
data class Coinone(
val result: String,
val errorCode: String,
val timestamp: String,
val crypto1: Ticker,
val crypto2: Ticker,
val crypto3: Ticker,
...
val cryptoN: Ticker)
Should I do like that? Is that only one solution?
I mean, if api data would be updated, I must update my pojo class. If I don't, apps will surely make crushes.
Is there any solution for making pojo class with api having similar structure?
Gson Object used when I don't know about Retrofit, GsonConverter and Kotlin not so much.

Related

Parse Json response from CoinGecko API with dynamic variable

I am trying to read the response from https://api.coingecko.com/api/v3/simple/price (for example with the fields: ids=bitcoin) where the "ids" field can be any cryptocurrency.
In order to read effectively the response i must have a data class like this one:
data class PortfolioCoinsDTO(
val bitcoin : PortfolioCoinItem
)
with an extra class:
data class PortfolioCoinItem(
val usd: Double,
val usd_market_cap: Double,
val usd_24h_change: Double
)
The above code works only when declaring the cryptocurrency as a variable in the DTO beforehand. Is there any way to solve this? So for example you can map the variable of the DTO data class to any cryptocurrency? (i am trying to see if with deserialization there might be a soluton).

how to create data class with this dynamic json keys while using retrofit and andorid jetpack libraries

this is json output:
{"query":{"apikey":"...","base_currency":"USD","timestamp":1635972203},"data":{"JPY":113.99127,"CNY":6.39464,"CHF":0.9114,"CAD":1.23881,"MXN":20.54423,"INR":74.44808,"BRL":5.57063,"RUB":71.80098,"KRW":1175.11443,"IDR":14295.1734,"TRY":9.63691,"SAR":3.75119,"SEK":8.52554,"NGN":410.22181,"PLN":3.94541,"ARS":99.81213,"NOK":8.49529,"TWD":27.78459,"IRR":42000.64577,"AED":3.67284,"COP":3827.77643,"THB":33.32047,"ZAR":15.23269,"DKK":6.40357,"MYR":4.15212,"SGD":1.34783,"ILS":3.11624,"HKD":7.78416,"EGP":15.7003,"PHP":50.65881,"CLP":811.73282,"PKR":169.4547,"IQD":1458.01958,"DZD":136.722,"KZT":428.93534,"QAR":3.6499,"CZK":21.94293,"PEN":4.0008,"RON":4.25921,"VND":22747.41599,"BDT":85.57148,"HUF":308.78687,"UAH":26.25062,"AOA":598.0065,"MAD":9.06226,"OMR":0.38491,"CUC":24.00026,"BYR":2.00003,"AZN":1.69502,"LKR":200.00259,"SDG":438.90856,"SYP":2511.07513,"MMK":1746.02836,"DOP":56.29093,"UZS":10690.31508,"KES":111.25137,"GTQ":7.73108,"URY":44.18107,"HRV":6.47553,"MOP":8.01811,"ETB":47.31305,"CRC":635.74442,"TZS":2298.03956,"TMT":3.49009,"TND":2.80635,"PAB":1.00002,"LBP":1505.5263,"RSD":101.16202,"LYD":4.54568,"GHS":6.00013,"YER":249.956,"BOB":6.82018,"BHD":0.377,"CDF":1999.22628,"PYG":6875.19435,"UGX":3550.05822,"SVC":8.7497,"TTD":6.74137,"AFN":90.84208,"NPR":119.13277,"HNL":24.06657,"BIH":1.68483,"BND":1.34753,"ISK":129.16264,"KHR":4060.117,"GEL":3.14003,"MZN":63.22108,"BWP":11.45513,"PGK":3.5113,"JMD":153.22216,"XAF":564.86281,"NAD":15.2189,"ALL":105.53113,"SSP":391.0052,"MUR":42.90097,"MNT":2830.04693,"NIO":35.21094,"LAK":10330.27262,"MKD":53.08156,"AMD":474.80501,"MGA":3928.06091,"XPF":102.48118,"TJS":11.26034,"HTG":98.0013,"BSD":1.00003,"MDL":17.41883,"RWF":1018.02194,"KGS":84.77099,"GNF":9510.20822,"SRD":21.40242,"SLL":10779.18736,"XOF":568.81159,"MWK":807.36713,"FJD":2.06806,"ERN":15.05028,"SZL":15.21372,"GYD":207.78611,"BIF":1980.25293,"KYD":0.82002,"MVR":15.42042,"LSL":15.23032,"LRD":146.80405,"CVE":94.95278,"DJF":177.50237,"SCR":14.42749,"SOS":575.00647,"GMD":52.15123,"KMF":424.6543,"STD":21.11031,"XRP":0.83002,"AUD":1.34372,"BGN":1.68394,"BTC":0.0159,"JOD":0.70801,"GBP":0.73402,"ETH":0.00022,"EUR":0.86112,"LTC":0,"NZD":1.40184}}
The data section contains many key value pairs, but their number and names vary according to base_currency. (For example if i send request with USD there is no USD key or if i send request with CNY there is no CNY key in data section)
So what kind of data class should I create so that I can use it with the retrofit and gsoncreator libraries. (I am also trying to use and learn jetpack android libraries if this is important)
i use that data classes: (I am not using gson annotations because i believe my variables names are correct and i try that it doesn't help)
data class ResponseFromApi(val data: Data,val query: Query)
data class Query(val apikey: String, val base_currency: String, val timestamp: Int)
data class Data(val hashmapForData: HashMap<String, Double>) (i suspect some values are integer but i am not sure)
it doesn't work. Maybe that's not the problem. I don't know but least i need to know, Are these classes correct? What is the proper way to do this.
And i don't know how to get error message from retrofit object so i can identify the problem. But this is another question.
Arpit Shukla's answer is correct.
ResponseFromApi(val query: Query, val data: Map<String,Double>)
It can deserialize key-value map to Map struct.

Post request body is not correct thus 400 error - Kotlin

I am facing a problem when trying to send an Http post request to the backend of my application. I am trying to send a post request like this :
{"a":[{"data":"https://news.google.com/rss/search?q=Pallini&hl=el"}]}
and instead it is being send something like this:
{"a":[{"data\":\"https://news.google.com/rss/search?q=Pallini&hl=el"}]}
or:
{"a":[{\"data\":\"https://news.google.com/rss/search?q=Pallini&hl=el\"}]}
So, I have a list that contains strings and every time I add the string that I want it to be shown in the json array, the code is like this:
var arrayListForA: ArrayList<JsonElement>? = arrayListOf()
config.forEach {
arrayListForA?.add(it)
}
The config is an another list that contains the jsons object as strings.
My question is, if there is any way to create the http post request body in Kotlin with the use of classes, objects etc, in a more automated way ?! for example, instead of a list with strings, I could use a list with Data class objects.
val dataList : ArrayList<Data> = arrayListOf()
where Data class is :
#Parcelize
data class Data(
#Expose #SerializedName("data") val data: String?
) : Parcelable
Is there any solution/idea to send the body of the post request as I need it ?
You can use retrofit and okhttp for this in Android. Retrofit helps you deal with networking easily. Also you will be able to post a custom data model as body in the api request. The interface will look something like given below. You can read more about retrofit here. retrofit
#POST(Urls.PURCHASE)
fun purchase(#Body purchaseAddonReqModel: PurchaseReqModel):Single<BaseResponse<EmptyResponse>>
Here you can add your custom model by adding the #Body annotation

How can I parse JSON such that if the structure is not as I intended it gracefully fails?

Reference: https://bytes.babbel.com/en/articles/2018-05-25-kotlin-gson-nullability.html
This article talks about one of the shortcomings of GSON with Kotlin. If we have a data class like this and try to break it:
data class User(
val email: String,
val firstName: String)
fun main(args: Array<String>) {
val json = """{
"email": null
}"""
val gson = Gson()
println(gson.fromJson(json, User::class.java).email)
}
as soon as we parse it and use the email field we'll return a NullPointerException. This is the intended behavior of GSON.
Is there a library out there that can give me an error like IllegalStateException and validate which field should be nullable? Or, is there a way to work around Moshi or GSON or any other JSON library so that I can get errors like that?
Gson doesn't give NullPointerException if a field is missing.It just ignores the missing fields of the object. For more details i would request you to share error log with exception and the code.

only classes are allowed on the left hand side of a class literal

I know a lot of similar questions here in StackOverflow, but nothing solved mine.
I have a generic data class:
data class ServiceCall<out T>(val result: T?, val exception: String?, val pagination: String?, val stringResult: String?)
I am trying to use like this:
Gson().fromJson(json, ServiceCall<SurveyListModel>::class.java).result
IDE shows error: only classes are allowed on the left hand side of a class literal
How to solve this? Thanks in advance.
You can't use generics with class, as easily observable here:
List<Int>::class.java
It gives you the same error. To use the generic typ in GSON deserialization, do what is suggested here:
https://stackoverflow.com/a/5554296/8073652
EDIT:
In Kotlin it looks like this:
val type: Type = object : TypeToken<ServiceCall<SurveyListModel>>() {}.type
Gson().fromJson<ServiceCall<SurveyListModel>>(json, type).result
Here's a small proof of concept, I've written:
class Token : TypeToken<List<Int>>()
val x: List<Int> = Gson().fromJson(Gson().toJson(arrayOf(1)), Token().type)
println(x)
If someone looking for the answer in Kotlin and Jackson.
val response = ObjectMapper().convertValue(dataObject, object: TypeReference<Map<String, Any>>(){})
If you want to pass a list of the generic objects pass it like this
listOf<MyModel>()::class
the function will be like this
fun myFunction ( inputList: KClass<T>){}

Categories

Resources