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.
CodePudding user response:
Add to app/build.gradle
kapt "com.squareup.moshi:moshi-kotlin-codegen:1.13.0"
Refactor your data class
@JsonClass(generateAdapter = true)
data class Item(
@Json(name = "productUid")
val productUid: String,
@Json(name = "quantity")
var quantity: Int
)
@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
CodePudding user response:
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?
)