I am new to Retrofit and I am having a weird problem. I am getting the following error -->
Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
However when I hit the endpoint with a curl command I get back a json array.
EDIT
Sorry for all of the edits. I may have put this question up prematurely. I am considering just removing the unnecessary code snippets if they are distracting. I put the edits at the top so you don't have to scroll down to see the latest problems. I think I may be in some real trouble with this last problem.
I found using a different model structure helps with the json conversion. I switched this
data class Jobs(
val job: List<JobPW>,
val status : String
)
To this
data class JobApiModel(
val jobs: List<Job>,
val status: String
)
And created a new Job class with the matching elements
data class Job(
@SerializedName("city")
@field:Json(name = "city")
val city: String,
@SerializedName("job_id")
@field:Json(name = "job_id")
val job_id: Int,
@SerializedName("owner_id_map")
@field:Json(name = "owner_id_map")
val owner_id_map: Int,
@SerializedName("status")
@field:Json(name = "status")
val status: Int,
@SerializedName("title")
val title: String,
val workers: List<Worker>,
val posters: List<PosterWithWorker>
)
This is the same object as JobPW but it is called Job which is the name of the property. Can you use a @SerializedName or something similar for class names? JobPW is a Room relation with a Job object and I can't call both classes Job. What is the best way to handle this?
So both
workers : List<Workers>
and
List<PosterWithWorker>
deserialize correctly. The other fields are all null and empty. Is there anything I am doing wrong or anything left to do?
EDIT
I am getting closer and it appears that after adding the outer jobs object around the array the call doesn't fail with an exception anymore. Instead, I get a null array (jobs = null) from Retrofit response = Jobs(job=null).
My Room Dao objects are below near the bottom of the post
For some reason, the JSON response looks different when using Retrofit. It looks like the following.
I should mention this is coming from a Firebase Realtime Database. When I use curl I just see the array, there is no wrapper object.
{
"jobs": [
{
"job": {
"city": "Toronto",
"job_id": 1,
"owner_id_map": 1,
"status": 0,
"title": "500 Posters in Toronto"
},
"posters": [
{
"poster": {
"job_id_map": 2,
"latitude": 43.64526533333377,
"locationDescription": "Union Station",
"longitude": -79.38060468539248,
"poster_id": 1,
"qr_code": "code2",
"worker_id": 1
},
"worker": [
{
"workerName": "Noris",
"worker_id": 1
}
]
},
{
"poster": {
"job_id_map": 2,
"latitude": 43.64295669900133,
"locationDescription": "Queen and Spadina",
"longitude": -79.39368099382459,
"poster_id": 2,
"qr_code": "code3",
"worker_id": 2
},
"worker": [
{
"workerName": "Jack",
"worker_id": 2
}
]
},
{
"poster": {
"job_id_map": 3,
"latitude": 43.76892443268843,
"locationDescription": "North York Civic Center",
"longitude": -79.41292484238735,
"poster_id": 3,
"qr_code": "code4",
"worker_id": 3
},
"worker": [
{
"workerName": "Nicky",
"worker_id": 3
}
]
}
],
"workers": [
{
"workerName": "Noris",
"worker_id": 1
},
{
"workerName": "Jack",
"worker_id": 2
},
{
"workerName": "Nicky",
"worker_id": 3
},
{
"workerName": "Davis",
"worker_id": 4
},
{
"workerName": "Argyle",
"worker_id": 5
},
{
"workerName": "James",
"worker_id": 6
}
]
},
{
"job": {
"city": "Montreal",
"job_id": 2,
"owner_id_map": 1,
"status": 1,
"title": "20 Posters in Montreal"
},
"posters": [],
"workers": [
{
"workerName": "Noris",
"worker_id": 1
},
{
"workerName": "Jack",
"worker_id": 2
},
{
"workerName": "Nicky",
"worker_id": 3
},
{
"workerName": "Davis",
"worker_id": 4
},
{
"workerName": "Argyle",
"worker_id": 5
},
{
"workerName": "James",
"worker_id": 6
}
]
},
{
"job": {
"city": "Ottawa",
"job_id": 3,
"owner_id_map": 2,
"status": 2,
"title": "350 Posters in Ottawa"
},
"posters": [
{
"poster": {
"job_id_map": 4,
"latitude": 43.63904362027761,
"locationDescription": "Harbourfront",
"longitude": -79.38193214610098,
"poster_id": 4,
"qr_code": "code5",
"worker_id": 0
},
"worker": []
},
{
"poster": {
"job_id_map": 5,
"latitude": 43.68347235901327,
"locationDescription": "Bathurst and St Clair",
"longitude": -79.41851002097324,
"poster_id": 5,
"qr_code": "code6",
"worker_id": 0
},
"worker": []
},
{
"poster": {
"job_id_map": 2,
"latitude": 43.6958481647278,
"locationDescription": "Dufferin and Eglinton",
"longitude": -79.45035794609939,
"poster_id": 6,
"qr_code": "code7",
"worker_id": 0
},
"worker": []
}
],
"workers": [
{
"workerName": "Noris",
"worker_id": 1
},
{
"workerName": "Jack",
"worker_id": 2
},
{
"workerName": "Nicky",
"worker_id": 3
},
{
"workerName": "Davis",
"worker_id": 4
},
{
"workerName": "Argyle",
"worker_id": 5
},
{
"workerName": "James",
"worker_id": 6
}
]
},
{
"job": {
"city": "Calgary",
"job_id": 4,
"owner_id_map": 2,
"status": 0,
"title": "10 Posters in Calgary"
},
"posters": [
{
"poster": {
"job_id_map": 2,
"latitude": 43.64526533333377,
"locationDescription": "Union Station",
"longitude": -79.38060468539248,
"poster_id": 1,
"qr_code": "code2",
"worker_id": 1
},
"worker": [
{
"workerName": "Noris",
"worker_id": 1
}
]
},
{
"poster": {
"job_id_map": 2,
"latitude": 43.64295669900133,
"locationDescription": "Queen and Spadina",
"longitude": -79.39368099382459,
"poster_id": 2,
"qr_code": "code3",
"worker_id": 2
},
"worker": [
{
"workerName": "Jack",
"worker_id": 2
}
]
},
{
"poster": {
"job_id_map": 3,
"latitude": 43.76892443268843,
"locationDescription": "North York Civic Center",
"longitude": -79.41292484238735,
"poster_id": 3,
"qr_code": "code4",
"worker_id": 3
},
"worker": [
{
"workerName": "Nicky",
"worker_id": 3
}
]
}
],
"workers": [
{
"workerName": "Noris",
"worker_id": 1
},
{
"workerName": "Jack",
"worker_id": 2
},
{
"workerName": "Nicky",
"worker_id": 3
},
{
"workerName": "Davis",
"worker_id": 4
},
{
"workerName": "Argyle",
"worker_id": 5
},
{
"workerName": "James",
"worker_id": 6
}
]
}
],
"status": "success"
}
Anyone understand why this maybe happening? Why would the curl response be different?
Here is the json from Firebase using curl.
[
{
"job": {
"city": "Toronto",
"job_id": 1,
"owner_id_map": 1,
"status": 0,
"title": "500 Posters in Toronto"
},
"posters": [
{
"poster": {
"job_id_map": 2,
"latitude": 43.64526533333377,
"locationDescription": "Union Station",
"longitude": -79.38060468539248,
"poster_id": 1,
"qr_code": "code2",
"worker_id": 1
},
"worker": [
{
"workerName": "Noris",
"worker_id": 1
}
]
},
{
"poster": {
"job_id_map": 2,
"latitude": 43.64295669900133,
"locationDescription": "Queen and Spadina",
"longitude": -79.39368099382459,
"poster_id": 2,
"qr_code": "code3",
"worker_id": 2
},
"worker": [
{
"workerName": "Jack",
"worker_id": 2
}
]
},
{
"poster": {
"job_id_map": 3,
"latitude": 43.76892443268843,
"locationDescription": "North York Civic Center",
"longitude": -79.41292484238735,
"poster_id": 3,
"qr_code": "code4",
"worker_id": 3
},
"worker": [
{
"workerName": "Nicky",
"worker_id": 3
}
]
}
],
"workers": [
{
"workerName": "Noris",
"worker_id": 1
},
{
"workerName": "Jack",
"worker_id": 2
},
{
"workerName": "Nicky",
"worker_id": 3
},
{
"workerName": "Davis",
"worker_id": 4
},
{
"workerName": "Argyle",
"worker_id": 5
},
{
"workerName": "James",
"worker_id": 6
}
]
},
{
"job": {
"city": "Montreal",
"job_id": 2,
"owner_id_map": 1,
"status": 1,
"title": "20 Posters in Montreal"
},
"workers": [
{
"workerName": "Noris",
"worker_id": 1
},
{
"workerName": "Jack",
"worker_id": 2
},
{
"workerName": "Nicky",
"worker_id": 3
},
{
"workerName": "Davis",
"worker_id": 4
},
{
"workerName": "Argyle",
"worker_id": 5
},
{
"workerName": "James",
"worker_id": 6
}
]
},
{
"job": {
"city": "Ottawa",
"job_id": 3,
"owner_id_map": 2,
"status": 2,
"title": "350 Posters in Ottawa"
},
"posters": [
{
"poster": {
"job_id_map": 4,
"latitude": 43.63904362027761,
"locationDescription": "Harbourfront",
"longitude": -79.38193214610098,
"poster_id": 4,
"qr_code": "code5",
"worker_id": 0
}
},
{
"poster": {
"job_id_map": 5,
"latitude": 43.68347235901327,
"locationDescription": "Bathurst and St Clair",
"longitude": -79.41851002097324,
"poster_id": 5,
"qr_code": "code6",
"worker_id": 0
}
},
{
"poster": {
"job_id_map": 2,
"latitude": 43.6958481647278,
"locationDescription": "Dufferin and Eglinton",
"longitude": -79.45035794609939,
"poster_id": 6,
"qr_code": "code7",
"worker_id": 0
}
}
],
"workers": [
{
"workerName": "Noris",
"worker_id": 1
},
{
"workerName": "Jack",
"worker_id": 2
},
{
"workerName": "Nicky",
"worker_id": 3
},
{
"workerName": "Davis",
"worker_id": 4
},
{
"workerName": "Argyle",
"worker_id": 5
},
{
"workerName": "James",
"worker_id": 6
}
]
},
{
"job": {
"city": "Calgary",
"job_id": 4,
"owner_id_map": 2,
"status": 0,
"title": "10 Posters in Calgary"
},
"posters": [
{
"poster": {
"job_id_map": 2,
"latitude": 43.64526533333377,
"locationDescription": "Union Station",
"longitude": -79.38060468539248,
"poster_id": 1,
"qr_code": "code2",
"worker_id": 1
},
"worker": [
{
"workerName": "Noris",
"worker_id": 1
}
]
},
{
"poster": {
"job_id_map": 2,
"latitude": 43.64295669900133,
"locationDescription": "Queen and Spadina",
"longitude": -79.39368099382459,
"poster_id": 2,
"qr_code": "code3",
"worker_id": 2
},
"worker": [
{
"workerName": "Jack",
"worker_id": 2
}
]
},
{
"poster": {
"job_id_map": 3,
"latitude": 43.76892443268843,
"locationDescription": "North York Civic Center",
"longitude": -79.41292484238735,
"poster_id": 3,
"qr_code": "code4",
"worker_id": 3
},
"worker": [
{
"workerName": "Nicky",
"worker_id": 3
}
]
}
],
"workers": [
{
"workerName": "Noris",
"worker_id": 1
},
{
"workerName": "Jack",
"worker_id": 2
},
{
"workerName": "Nicky",
"worker_id": 3
},
{
"workerName": "Davis",
"worker_id": 4
},
{
"workerName": "Argyle",
"worker_id": 5
},
{
"workerName": "James",
"worker_id": 6
}
]
}
]
Here is my Retrofit API call
@GET("/jobs.json")
suspend fun getJobsList() : Response<List<JobPW>>
I am assuming there is an issue with a nested object but I don't know how to debug it.
Here are my models; which are also Room objects
data class JobPW(
@Embedded val job: Job,
@Relation(
parentColumn = "job_id",
entityColumn = "worker_id",
associateBy = Junction(JobWorkerCrossRef::class)
)
val workers: List<Worker>,
@Relation(
entity = Poster::class,
parentColumn = "job_id",
entityColumn = "job_id_map"
)
val posters: List<PosterWithWorker>
) : Serializable
data class PosterWithWorker(
@Embedded val poster: Poster,
@Relation(
parentColumn = "worker_id",
entityColumn = "worker_id",
associateBy = Junction(
value = PosterWorkerCrossRef::class,
parentColumn = "poster_id_map",
entityColumn = "worker_id_map"
)
)
val worker: List<Worker>
) : Serializa
package com.davidozersky.posterpal.database.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.PrimaryKey
import java.io.Serializable
@Entity(
foreignKeys = [
ForeignKey(
entity = Owner::class,
parentColumns = ["owner_id"],
childColumns = ["owner_id_map"],
onDelete = ForeignKey.CASCADE,
onUpdate = ForeignKey.CASCADE
)
]
)
data class Job (
@PrimaryKey val job_id: Long,
val status: Int,
@ColumnInfo(index = true)
val owner_id_map: Long,
val title: String,
val city: String
) : Serializable
package com.davidozersky.posterpal.database.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.io.Serializable
@Entity
class Worker(
@PrimaryKey
@ColumnInfo(name = "worker_id")
val worker_id: Long,
val workerName: String,
) : Serializable
Poster
package com.davidozersky.posterpal.database.entities
import androidx.room.*
@Entity(
foreignKeys = [
ForeignKey(
entity = Job::class,
parentColumns = ["job_id"],
childColumns = ["job_id_map"],
onDelete = ForeignKey.CASCADE,
onUpdate = ForeignKey.CASCADE
)
]
)
data class Poster (
@PrimaryKey val poster_id: Long,
@ColumnInfo(index = true)
val job_id_map: Long,
val qr_code: String,
val worker_id: Long,
val latitude: Double,
val longitude: Double,
val locationDescription: String,
)
I tried using OkHttp directly with the HttpLogger and the call responds with a 200 and it logs out the same json
[{"job":{"city":"Toronto","job_id":1,"owner_id_map":1,"status":0,"title":"500 Posters in Toronto"},"posters":[{"poster":{"job_id_map":2,"latitude":43.64526533333377,"locationDescription":"Union Station","longitude":-79.38060468539248,"poster_id":1,"qr_code":"code2","worker_id":1},"worker":[{"workerName":"Noris","worker_id":1}]},{"poster":{"job_id_map":2,"latitude":43.64295669900133,"locationDescription":"Queen and Spadina","longitude":-79.39368099382459,"poster_id":2,"qr_code":"code3","worker_id":2},"worker":[{"workerName":"Jack","worker_id":2}]},{"poster":{"job_id_map":3,"latitude":43.76892443268843,"locationDescription":"North York Civic Center","longitude":-79.41292484238735,"poster_id":3,"qr_code":"code4","worker_id":3},"worker":[{"workerName":"Nicky","worker_id":3}]}],"workers":[{"workerName":"Noris","worker_id":1},{"workerName":"Jack","worker_id":2},{"workerName":"Nicky","worker_id":3},{"workerName":"Davis","worker_id":4},{"workerName":"Argyle","worker_id":5},{"workerName":"James","worker_id":6}]},{"job":{"city":"Montreal","job_id":2,"owner_id_map":1,"status":1,"title":"20 Posters in Montreal"},"workers":[{"workerName":"Noris","worker_id":1},{"workerName":"Jack","worker_id":2},{"workerName":"Nicky","worker_id":3},{"workerName":"Davis","worker_id":4},{"workerName":"Argyle","worker_id":5},{"workerName":"James","worker_id":6}]},{"job":{"city":"Ottawa","job_id":3,"owner_id_map":2,"status":2,"title":"350 Posters in Ottawa"},"posters":[{"poster":{"job_id_map":4,"latitude":43.63904362027761,"locationDescription":"Harbourfront","longitude":-79.38193214610098,"poster_id":4,"qr_code":"code5","worker_id":0}},{"poster":{"job_id_map":5,"latitude":43.68347235901327,"locationDescription":"Bathurst and St Clair","longitude":-79.41851002097324,"poster_id":5,"qr_code":"code6","worker_id":0}},{"poster":{"job_id_map":2,"latitude":43.6958481647278,"locationDescription":"Dufferin and Eglinton","longitude":-79.45035794609939,"poster_id":6,"qr_code":"code7","worker_id":0}}],"workers":[{"workerName":"Noris","worker_id":1},{"workerName":"Jack","worker_id":2},{"workerName":"Nicky","worker_id":3},{"workerName":"Davis","worker_id":4},{"workerName":"Argyle","worker_id":5},{"workerName":"James","worker_id":6}]},{"job":{"city":"Calgary","job_id":4,"owner_id_map":2,"status":0,"title":"10 Posters in Calgary"},"posters":[{"poster":{"job_id_map":2,"latitude":43.64526533333377,"locationDescription":"Union Station","longitude":-79.38060468539248,"poster_id":1,"qr_code":"code2","worker_id":1},"worker":[{"workerName":"Noris","worker_id":1}]},{"poster":{"job_id_map":2,"latitude":43.64295669900133,"locationDescription":"Queen and Spadina","longitude":-79.39368099382459,"poster_id":2,"qr_code":"code3","worker_id":2},"worker":[{"workerName":"Jack","worker_id":2}]},{"poster":{"job_id_map":3,"latitude":43.76892443268843,"locationDescription":"North York Civic Center","longitude":-79.41292484238735,"poster_id":3,"qr_code":"code4","worker_id":3},"worker":[{"workerName":"Nicky","worker_id":3}]}],"workers":[{"workerName":"Noris","worker_id":1},{"workerName":"Jack","worker_id":2},{"workerName":"Nicky","worker_id":3},{"workerName":"Davis","worker_id":4},{"workerName":"Argyle","worker_id":5},{"workerName":"James","worker_id":6}]}]