Moshi: Expected BEGIN_ARRAY but was BEGIN_OBJECT at path - kotlin

I get the following error from Moshi: Expected BEGIN_ARRAY but was BEGIN_OBJECT at path
This is my interface:
interface ApiService {
#GET("movie/popular")
suspend fun getTopRatedMovies(
#Query("api_key") apiKey: String = BuildConfig.API_KEY,
#Query("page") page: Int = 1
): List<TopRatedMovies>
data class
data class TopRatedMovies(
#Json(name = "title") val title: String,
#Json(name = "poster_path") val posterPath: String,
)
The response looks like this:
I know that there are some other questions with the same title but those didn't help me.

From the function's return type (List<TopRatedMovies>), Moshi is expecting your API to return a list, but it's returning an object ({"page": ..., "results": [...]}) instead.
To handle this, you can create a TopRatedMoviesPage class like this:
data class TopRatedMoviesPage(
#Json(name = "page") val page: Int,
#Json(name = "results") val results: List<TopRatedMovies>,
)
And change your API definition to this:
#GET("movie/popular")
suspend fun getTopRatedMovies(
#Query("api_key") apiKey: String = BuildConfig.API_KEY,
#Query("page") page: Int = 1
): TopRatedMoviesPage

Related

Jackon JSON Adding deserializer module doesn't work, but annotation on class does

I am trying to implement a custom deserializer and when I try to install it on the ObjectMapper it never gets invoked, but when I use it directly as an annotation on the class, it does. Can someone explain why and how I can actually install it on the object mapper itself?
This is never invoked
val bug = ObjectMapper().registerModule(KotlinModule.Builder().build())
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.registerModule(SimpleModule().addDeserializer(Bug::class.java, BugDeserializer()))
.readValue(bugStream, Bug::class.java)
data class Bug(
#JsonProperty("rptno")
val id: Long,
#JsonProperty("status")
#JsonDeserialize(using = StatusDeserializer::class)
val status: Status,
#JsonProperty("reported_date")
val reportedDate:Instant,
#JsonProperty("updated_date")
val updatedDate: Instant,
// val pillar: String = "",
#JsonProperty("product_id")
#JsonDeserialize(using = ProductDeserializer::class)
val product: Product,
#JsonProperty("assignee")
val assignee: String,
// val serviceRequests: List<Long> = listOf(),
#JsonProperty("subject")
val title: String,
#JsonProperty("bug_type")
val type: String
)
But, this does:
val bug = ObjectMapper().registerModule(KotlinModule.Builder().build())
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.readValue(bugStream, Bug::class.java)
#JsonDeserialize(using = BugDeserializer::class)
data class Bug(
#JsonProperty("rptno")
val id: Long,
#JsonProperty("status")
#JsonDeserialize(using = StatusDeserializer::class)
val status: Status,
#JsonProperty("reported_date")
val reportedDate:Instant,
#JsonProperty("updated_date")
val updatedDate: Instant,
// val pillar: String = "",
#JsonProperty("product_id")
#JsonDeserialize(using = ProductDeserializer::class)
val product: Product,
#JsonProperty("assignee")
val assignee: String,
// val serviceRequests: List<Long> = listOf(),
#JsonProperty("subject")
val title: String,
#JsonProperty("bug_type")
val type: String
)
```kotlin

cant understand this kotlin companion object code

I went through this code example but i can't get it to run neither do understand what it does exactly.
data class Order(
val id: String,
val name: String,
val data:String
)
data class OrderResponse(
val id: String,
val name: String,
val data: String
) {
companion object {
fun Order.toOrderResponse() = OrderResponse(
id = id,
name = name,
data = data ?: "",
)
}
}
The function in the companion object extends Order with a help function to turn Order instances into OrderResponse instances. So for example like
val order = Order("a", "b", "c")
val orderResponse = order.toOrderResponse()

How do I get context inside a companion object that is inside a data class Kotlin?

I'm trying to use a resource string inside a companion object that is inside a data class. but I don't Know how to obtain context in that case in Kotlin.
Anyone knows how to do it?
data class PhoneCall(
val type: String,
val code: String,
val description: String){
companion object{
const val SOLUTION_NO_SOLUTION = "NO_SOLUTION"
const val SOLUTION_TOMORROW = "71_INAT"
const val SOLUTION_TODAY = "72_INAT"
val solutions = listOf(
PhoneCall(Service.Traffic.PICK_UP, SOLUTION_NO_SOLUTION, Resources.getSystem().getString(R.string.makeService))
)
}
I need to use a resource string in the 3 parameter, but I'm not able to get the context.
You can modify you PhoneCall model to store a string resource id instead of the actual string.
data class PhoneCall(
val type: String,
val code: String,
#StringRes val description: Int
) {
companion object {
const val SOLUTION_NO_SOLUTION = "NO_SOLUTION"
const val SOLUTION_TOMORROW = "71_INAT"
const val SOLUTION_TODAY = "72_INAT"
val solutions = listOf(
PhoneCall(Service.Traffic.PICK_UP, SOLUTION_NO_SOLUTION, R.string.makeService)
)
}
}
Then, when you need to display this data in the UI (say a TextView), you can fetch the string from the resource id.
descriptionTextView.text = getString(phoneCall.description)

How to restrict Int values bound to database column?

data class:
// Entity of query
#Entity(tableName = TABLE_NAME)
data class HistoryItem(
#PrimaryKey(autoGenerate = true)
val id: Int,
#ColumnInfo(name = SEARCHED_DOMAIN)
val searchedDomain: String,
#ColumnInfo(name = STATUS)
val status: Int,
)
And object of statuses:
object Statuses {
const val FAILURE = 0
const val NOT_FOUND = 1
const val FOUND = 2
}
How to make val status: Int to always be FAILURE or NOT_FOUND or FOUND? I think it should looks like this:
#Status
#ColumnInfo(name = STATUS)
val status: Int
But how to do it?
I would recommend using an enum class for this:
enum class Status {
FAILURE, NOT_FOUND, FOUND;
}
#Entity(tableName = TABLE_NAME)
data class HistoryItem(
#PrimaryKey(autoGenerate = true)
val id: Int,
#ColumnInfo(name = SEARCHED_DOMAIN)
val searchedDomain: String,
#ColumnInfo(name = STATUS)
val status: Status
)
However, older versions of Android Room (prior to 2.3.0) do not automatically convert enum classes, so if you're using these you will need to use a type convertor:
class Converters {
#TypeConverter
fun toStatus(value: Int) = enumValues<Status>()[value]
#TypeConverter
fun fromStatus(value: Status) = value.ordinal
}
Which requires you to add the following to your database definition:
#TypeConverters(Converters::class)
See also this answer.

How to parse LinkedHashMap in moshi (kotlin)

I am trying to create a JSON adapter for the following json
{
"message": {
"affenpinscher": [],
"african": [],
"airedale": [],
"akita": [],
"appenzeller": [],
"australian": [
"shepherd"
]
},
"status": "success"
}
I have tried the following
#JsonClass(generateAdapter = true)
data class BreedList(
val message: HashMap<String,List<String>> = HashMap<String,List<String>>()
)
and
#JsonClass(generateAdapter = true)
data class BreedList(
val message: Breed
)
#JsonClass(generateAdapter = true)
data class Breed(
val breed: List<String>
)
But both scenarios give me the errors, is there a way to parse the following object, I need the key as well as the list from the response
There is no need to create a custom adapter.
To parse the JSON you posted:
data class Base (
#field:Json(name = "message")
val message : Message,
#field:Json(name = "status")
val status : String
)
data class Message (
#field:Json(name = "affenpinscher")
val affenpinscher : List<String>,
#field:Json(name = "african")
val african : List<String>,
#field:Json(name = "airedale")
val airedale : List<String>,
#field:Json(name = "akita")
val akita : List<String>,
#field:Json(name = "appenzeller")
val appenzeller : List<String>,
#field:Json(name = "australian")
val australian : List<String>
)
Note: instead of String you can use whatever data type you need or create custom classes like Message.