I had the response structure given below
#JsonClass(generateAdapter = true)
data class ResponseMessage(
#field:Json(name = "ClientID") val clientID: String,
#field:Json(name = "MessageID") val messageID: String,
#field:Json(name = "Payload") val payload: Payload,
#field:Json(name = "Timeout") val timeout: Int,
#field:Json(name = "Timestamp") val timestamp: Long,
#field:Json(name = "Type") val type: String
)
#JsonClass(generateAdapter = true)
data class Payload(
#field:Json(name = "Action") val action: String,
#field:Json(name = "Params") val params: Params?
)
#JsonClass(generateAdapter = true)
data class Params(
#field:Json(name = "room") val userDetails: UserDetails?,
#field:Json(name = "configuration") val configurationDetails: ConfigurationDetails?,
#field:Json(name = "category") val category: String?
)
Here Params could be changed in response as per the requested service. However in some cases params will not required at all. How this can be done by making Params as Generic Type so that when i need UserDetails i will pass that and likewise for other params.
Related
I'm trying to make a post with retrofit and moshi but keep getting the error mess
com.squareup.moshi.JsonDataException: Expected BEGIN_OBJECT but was STRING at path $
I can't seem to understand why this is so. This is a sample of the json tested on postman:
{
"customerName": "Name",
"customerPhoneNo": "090000000",
"customerAddress": "Address",
"note": "Please",
"items" : [{
"productUid": "5633e1f1-8b00-46de-b73e-43799245a4e8",
"quantity" : "3"
},{
"ProductUid": "fca3ffb1-0130-4e47-b499-721d046c1e32",
"Quantity" : "5"
},
{
"ProductUid": "6a7f3e24-03ff-408a-b67e-8530d411390c",
"Quantity" : "2"
}]
}
My data classes are set up like so:
#Parcelize
data class Order(
val items: List<Item>?,
val customerName: String,
val customerPhoneNo: String,
val customerAddress: String,
val note: String
) : Parcelable
and
#Parcelize
data class Item(
val productUid: String,
var quantity: Int
) : Parcelable
Service utils look like:
interface ProductService {
#Headers("Content-Type: application/json")
#POST("/api/order/saveorder")
suspend fun postProds(#Body order: Order
): Response<Order>
#GET("/api/product/allproducts")
suspend fun getProds(): Response<List<ProdsItem>>
}
private val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
object Network {
private val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(MoshiConverterFactory.create(moshi)
.asLenient()
)
.build()
object ProdsApi {
val retrofitService: ProductService by lazy {
retrofit.create(ProductService::class.java)
}
}
}
The sendOrder function is set up like so:
suspend fun sendOrder(order: Order) {
withContext(Dispatchers.Main){
try {
val orderResponse = Network.ProdsApi.retrofitService.postProds(
order )
}
catch (e: Exception) {
Timber.e(e)
}
}
}
The GET request works perfectly.
Any help on this would be appreciated please.
In your Item Data Class you are using quantity as an Int but if you see the Postman JSON response it is a String.
So your class should be like:
data class Item(
#Json(name = "productUid")
val productUid: String?,
#Json(name = "quantity")
var quantity: String
)
Also as I see the key in your JSON response are written in two different ways.
For example your "Product ID" is written as "productUid" in one of the object and is written as "ProductUid" in another object.
So your complete Item Data Class should more look like this :
data class Item(
#Json(name = "productUid")
val productUid: String?,
#Json(name = "ProductUid")
val productUid: String?,
#Json(name = "quantity")
val quantity: String?,
#Json(name = "Quantity")
val quantity: String?
)
Add to app/build.gradle
kapt "com.squareup.moshi:moshi-kotlin-codegen:1.13.0"
Refactor your data class
check the key in your item and replace with right one
if productUid or ProductUid
quantity or Quantity
#JsonClass(generateAdapter = true)
data class Item(
#Json(name = "productUid")
val productUid: String,
#Json(name = "quantity")
var quantity: String
)
#JsonClass(generateAdapter = true)
data class Order(
#Json(name = "items")
val items: List<Item>,
#Json(name = "customerName")
val customerName: String,
#Json(name = "customerPhoneNo")
val customerPhoneNo: String,
#Json(name = "customerAddress")
val customerAddress: String,
#Json(name = "note")
val note: String
)
and try it again
[{"id":1,"first_name":"Lillis","last_name":"Hawgood"," cars":[ {"item":"Savana 1500"}, {"item":"Vibe"}, {"item":"Estate"} ]}]
data class MyData( val id: Int = 0, val first_name: String = "", val last_name: String = "", val cars: List
)
class Car { #Json(name = "item") var item: String? = null How to use Item in Data class the how ot print in main clas using moshi txtResult.text = "" for (myDataLst in myDataList ?: emptyList()) { txtResult.append("${myDataLst.first_name} - ${myDataLst.last_name} - ${myDataLst.cars} \n") }enter code here
I tried this way only first name and last showing but for cars showing some worng infor
Try this data classes i transform it using Json to Data Class plugin.
data class MyData(
val cars: List<Car>,
val first_name: String,
val id: Int,
val last_name: String
)
data class Car(
val item: String
)
class car : ArrayList<MyData>()
Firstly, please format your code, it's hard to read your code.
Secondly, you can use the Moshi like this:
#JsonClass(generateAdapter = true)
data class MyData(
#Json(name = "id") val id: String,
#Json(name = "first_name") val firstName: String,
#Json(name = "last_name") val lastName: String,
#Json(name = "cars") val cars: List<Car>
)
#JsonClass(generateAdapter = true)
data class Car(
#Json(name = "item") val item: String
)
Here is my entity class:
#Entity
data class User(
#PrimaryKey
#Json(name = "id") val userId: String,
#Json(name = "login") val userName: String,
#Json(name = "avatar_url") val userAvatar: String,
val profile: Profile? = null
) : Serializable
Here is my Profile data class
data class Profile(
val avatar_url: String,
val bio: String,
val blog: String,
val company: Any,
val created_at: String,
val email: Any,
val events_url: String,
val followers: Int,
val followers_url: String,
val following: Int,
val following_url: String,
val gists_url: String,
val gravatar_id: String,
val hireable: Boolean,
val html_url: String,
val id: Int,
val location: String,
val login: String,
val name: String,
val node_id: String,
val organizations_url: String,
val public_gists: Int,
val public_repos: Int,
val received_events_url: String,
val repos_url: String,
val site_admin: Boolean,
val starred_url: String,
val subscriptions_url: String,
val twitter_username: Any,
val type: String,
val updated_at: String,
val url: String
) : Serializable
but every time I try to insert data into the table I am getting the error, how can I insert null data object in table while using room database?
The issue here is that Room doesn't know how to insert attribute of type Profile to the table.
The simple solution would be to use a type converter. Something like the following:
class DatabaseConverters {
#TypeConverter
fun toProfile(profileJson: String): Profile? {
return <Create a Profile object out of a JSON string>
}
#TypeConverter
fun fromProfile(profile: Profile?): String {
return <JSON string representation of Profile object>
}
}
In your case - you can use "" (empty string) when Profile is null.
More info about converters: Here
This is not retrofit but manual parsing in a Firebase message handler service. I am using KotlinJsonAdapterFactory() when building my Moshi instance.
For some reason it thinks one of the nodes is an array when I am asking for it to be parsed as an object. Here is the JSON:
[
{
"$": {
"updateOrigin": "CIS",
"requestSource": "at20",
"requestID": "0000000000004144"
},
"TS": [{
"$": {
"rid": "202008207681819",
"uid": "L81819",
"ssd": "2020-08-20"
},
"Location": [{
"$": {
"tpl": "PADTON",
"wtd": "17:28",
"ptd": "17:28"
},
"dep": [{
"$": {
"et": "17:28",
"src": "Darwin"
}
}
],
"plat": [{
"_": "2",
"$": {
"platsup": "true",
"cisPlatsup": "true",
"platsrc": "M"
}
}
]
}
]
}
]
}
]
And here are my Data classes:
package com.cniekirk.traintimes.model
import com.squareup.moshi.Json
data class PushPortMessage(
val pushPortMessageItems: List<PushPortMessageItem>?
)
data class PushPortMessageItem(
#Json(name = "TS")
val tS: List<TS>?,
#Json(name = "$")
val messageAttrs: MessageAttrs?
)
data class TS(
#Json(name = "LateReason")
val lateReason: List<String>?,
#Json(name = "Location")
val location: List<Location>?,
#Json(name = "$")
val tsAttrs: TSAttrs?
)
data class MessageAttrs(
#Json(name = "updateOrigin")
val updateOrigin: String?
)
data class Location(
#Json(name = "arr")
val arr: List<Arr>?,
#Json(name = "dep")
val dep: List<Dep>?,
#Json(name = "pass")
val pass: List<Pass>?,
#Json(name = "plat")
val plat: List<Plat>?,
#Json(name = "$")
val stationAttrs: StationAttrs?
)
data class TSAttrs(
#Json(name = "rid")
val rid: String?,
#Json(name = "ssd")
val ssd: String?,
#Json(name = "uid")
val uid: String?
)
data class Arr(
#Json(name = "$")
val arrPassAttrs: List<ArrPassAttrs>?
)
data class Dep(
#Json(name = "$")
var depAttrs: DepAttrs?
)
data class Pass(
#Json(name = "$")
val arrPassAttrs: ArrPassAttrs?
)
data class Plat(
#Json(name = "_")
val platform: Int?,
#Json(name = "$")
val platAttrs: PlatAttrs?
)
data class PlatAttrs(
#Json(name = "platsup")
val platsup: Boolean?,
#Json(name = "cisPlatsup")
val cisPlatsup: Boolean?
)
data class StationAttrs(
#Json(name = "pta")
val pta: String?,
#Json(name = "ptd")
val ptd: String?,
#Json(name = "tpl")
val tpl: String?,
#Json(name = "wta")
val wta: String?,
#Json(name = "wtd")
val wtd: String?,
#Json(name = "wtp")
val wtp: String?
)
data class ArrPassAttrs(
#Json(name = "delayed")
val delayed: String?,
#Json(name = "et")
val et: String?,
#Json(name = "src")
val src: String?
)
data class DepAttrs(
#Json(name = "delayed")
val delayed: String?,
#Json(name = "et")
val et: String?,
#Json(name = "etUnknown")
val etUnknown: String?,
#Json(name = "etmin")
val etmin: String?,
#Json(name = "src")
val src: String?
)
I may just be being stupid but I can't find the issue. Here is how I'm parsing the JSON:
val pushPortMessage = data["body"]
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
val pushPortAdapter = moshi.adapter(PushPortMessage::class.java)
pushPortMessage?.let {
val msg = pushPortAdapter.fromJson(pushPortMessage)
println(msg)
}
you are parsing a list of objects not object so the parsing should be something like this
val pushPortMessage = data["body"]
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
val listType = Types.newParameterizedType(List::class.java, PushPortMessageItem::class.java)
val adapter: JsonAdapter<List<PushPortMessageItem>> = moshi.adapter(listType)
val pushPortMessageList = adapter.fromJson(pushPortMessage )
I've recently switched from Gson to Moshi and am having trouble parsing some Json.
{
"access_token": "-LNe2LQ7DQH5Y2zs_W5iUumKuaUE",
"token_type": "bearer",
"device_id": "461f-837e-af5050c92fe9",
"expires_in": 3600,
"scope": "*"
}
And here's the model class:
data class AuthToken(
#Json(name = "access_token") val accessToken: String,
#Json(name = "token_type") val tokenType: String,
#Json(name = "device_id") val deviceId: String,
#Json(name = "expires_in") val expiresIn: Int,
#Json(name = "scope") val scope: String
)
Whenever I switch to using Moshi in my retrofit client, I receive the following error:
java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull
I have made the field nullable, however it is always deserialized as null. I've checked my retrofit response and it's (obviously) the same when using either Gson or Moshi. What am I doing wrong?
For some reason, when I explicitly tell the AuthToken class to generate an adapter - I receive no null values.
#JsonClass(generateAdapter = true)
data class AuthToken(
#Json(name = "access_token") val accessToken: String,
#Json(name = "token_type") val tokenType: String,
#Json(name = "device_id") val deviceId: String,
#Json(name = "expires_in") val expiresIn: Int,
#Json(name = "scope") val scope: String
)