0

I'm trying to retrieve data and display them in a recycler view. I'm working with retrofit, making a get request.. Everything is fine, except: it won't display data in the recycler because it says: "Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2". I also used the kotlin data class file from JSON plugin to generate data classes from the response. I don't know what to do, I'm stuck..

Here are my classes:

ApiClient.kt

object ApiClient {

private const val BASE_URL: String = "https://dev.fastbeach.it/api/"

private val gson : Gson by lazy {
    GsonBuilder().setLenient().create()
}

private val httpClient : OkHttpClient by lazy {
    OkHttpClient.Builder().build()
}

private val retrofit : Retrofit by lazy {
    Retrofit.Builder()
        .baseUrl(BASE_URL)
        .client(httpClient)
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build()
}

val apiService :  ApiService by lazy{
    retrofit.create(ApiService::class.java)
}

ApiService.kt

interface ApiService {

@GET("tenant/searchAllWithPagesAndFilters")
fun getUsers(
    @Query("reservationEnabled") reservationEnabled:Boolean,
    @Query("page") page:Int,
    @Query("size") size:Int,
    @Query("sort") sort:String,
    @Query("direction") direction:String
): Call<MutableList<User>>

UserRepository.kt

object UserRepository {

fun getMutableLiveData(context: Context) : MutableLiveData<ArrayList<User>>{

    val mutableLiveData = MutableLiveData<ArrayList<User>>()

    context.showProgressBar()

    ApiClient.apiService.getUsers(true,0,5,"order","ASC").enqueue(object : Callback<MutableList<User>> {
        override fun onFailure(call: Call<MutableList<User>>, t: Throwable) {
            hideProgressBar()
            Log.e("error", t.localizedMessage)
        }

        override fun onResponse(
            call: Call<MutableList<User>>,
            response: Response<MutableList<User>>
        ) {
            hideProgressBar()
            val usersResponse = response.body()
            usersResponse?.let { mutableLiveData.value = it as ArrayList<User> }
        }

    })

    return mutableLiveData
}

UserViewModel.kt

class UserViewModel(private val context: Context) : ViewModel() {

private var listData = MutableLiveData<ArrayList<User>>()

init{
    val userRepository : UserRepository by lazy {
        UserRepository
    }
    if(context.isInternetAvailable()) {
        listData = userRepository.getMutableLiveData(context)
    }
}

fun getData() : MutableLiveData<ArrayList<User>>{
    return listData
}

MainActivity.kt

class MainActivity : AppCompatActivity() {

private lateinit var listUsers: MutableList<User>
private lateinit var adapter: UsersAdapter

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    recycler_main.layoutManager = LinearLayoutManager(this@MainActivity)
    listUsers = mutableListOf<User>()
    adapter = UsersAdapter(this,
        listUsers
    )
    recycler_main.adapter = adapter

    val userViewModel = ViewModelProviders.of(this,UserViewModelFactory(this)).get(UserViewModel::class.java)
    userViewModel.getData().observe(this,object:Observer<ArrayList<User>>{
        override fun onChanged(t: ArrayList<User>?) {
            listUsers.clear()
            t?.let { listUsers.addAll(it) }
            adapter.notifyDataSetChanged()
        }

    })

}

API response from POSTMAN

{
"content": [
    {
        "id": "609d2d79be5f8e42d9c13e41",
        "name": "bagno-sirena-posillipo",
        "title": "Bagno Sirena Posillipo",
        "tenantName": "Bagno Sirena",
        "tenantCode": "BSI",
        "description": "E' uno dei siti balneari più antichi, inserito in un posto incantevole a ridosso del Palazzo Donn'Anna, in una piccola insenatura riparata e quindi usufruibile in tutti i mesi dell'anno per chi vuole in piena città trascorrere qualche ora di relax respirando aria di mare e conservare l'abbronzatura estiva.\nI gestori si stanno impegnando per migliorare i servizi della location.\nVorremmo condividere con tutti gli amanti del mare e della costa di Posillipo questa meraviglia che abbiamo.\nVeniteci a trovare e avrete modo di constatare questa bellezza.",
        "confirmBookingsRequired": false,
        "paymentRequired": true,
        "fee": 1.0,
        "foodFee": 0.5,
        "feePercentage": 0.02,
        "foodFeePercentage": 0.02,
        "percentage": true,
        "signInSignOnEnabled": true,
        "qrCodeValidation": true,
        "tenantImage": {},
        "tenantOtherImage": [],
        "type": "Beach",
        "enabledServices": [],
        "master": false,
        "comune": "Napoli",
        "comuneId": "063049",
        "address": {
            "address": "Via Posillipo, 357",
            "city": "Napoli",
            "province": "NA",
            "country": "Italia",
            "postalNumber": "80123",
            "phoneNumber": "081 769 2885",
            "web": "https://www.facebook.com/bagnosirenanapoli/",
            "email": "development@synclab.it"
        },
        "reservationEnabled": true,
        "foodEnabled": true,
        "reservationWithoutMapButWithCart": false,
        "criteriaNumPlaces": {},
        "supportedServices": [
            {
                "id": "5f04a23f968f9926b4b76746",
                "name": "Lettini",
                "description": "Lettini",
                "supported": true,
                "tenantTypes": []
            },
            {
                "id": "5f04a240968f9926b4b76747",
                "name": "Ombrelloni",
                "description": "Ombrelloni",
                "supported": true,
                "tenantTypes": []
            },
            {
                "id": "5f04a240968f9926b4b76748",
                "name": "Sdraio",
                "description": "Sdraio",
                "supported": false,
                "tenantTypes": []
            },
            {
                "id": "5f04a240968f9926b4b76749",
                "name": "Parcheggio",
                "description": "Parcheggio",
                "supported": false,
                "tenantTypes": []
            },
            {
                "id": "5f04a240968f9926b4b7674a",
                "name": "Lettoni",
                "description": "Lettoni",
                "supported": false,
                "tenantTypes": []
            },
            {
                "id": "5f04a240968f9926b4b7674b",
                "name": "Accessibilita",
                "description": "Accesso disabili\n",
                "supported": false,
                "tenantTypes": []
            },
            {
                "id": "5f04a240968f9926b4b7674c",
                "name": "Area_baby",
                "description": "Area baby",
                "supported": false,
                "tenantTypes": []
            },
            {
                "id": "5f04a240968f9926b4b7674d",
                "name": "Ristorante",
                "description": "Ristorante",
                "supported": true,
                "tenantTypes": []
            },
            {
                "id": "5f04a240968f9926b4b7674e",
                "name": "Bar",
                "description": "Bar",
                "supported": false,
                "tenantTypes": []
            },
            {
                "id": "5f04a240968f9926b4b7674f",
                "name": "Alcolici",
                "description": "Alcolici",
                "supported": false,
                "tenantTypes": []
            },
            {
                "id": "5f04a240968f9926b4b76750",
                "name": "Gazebo",
                "description": "Gazebo",
                "supported": false,
                "tenantTypes": []
            },
            {
                "id": "5f04a240968f9926b4b76751",
                "name": "Pagoda",
                "description": "Pagoda",
                "supported": false,
                "tenantTypes": []
            },
            {
                "id": "5f04a240968f9926b4b76752",
                "name": "Wc",
                "description": "Wc",
                "supported": true,
                "tenantTypes": []
            },
            {
                "id": "60c72a1709e2081fa9b6d422",
                "name": "Wi-fi",
                "description": "Wi-fi",
                "supported": false,
                "tenantTypes": []
            },
            {
                "id": "60c72a2509e2081fa9b6d423",
                "name": "Accesso_animali",
                "description": "Animali",
                "supported": false,
                "tenantTypes": []
            },
            {
                "id": "60c72a2709e2081fa9b6d424",
                "name": "Animazione",
                "description": "Animazione",
                "supported": false,
                "tenantTypes": []
            },
            {
                "id": "60c72a2a09e2081fa9b6d425",
                "name": "Cabine",
                "description": "Cabine",
                "supported": false,
                "tenantTypes": []
            },
            {
                "id": "60c72a4109e2081fa9b6d426",
                "name": "Piscina",
                "description": "Piscina",
                "supported": false,
                "tenantTypes": []
            },
            {
                "id": "60ec61341dbc2d4ed0d130ff",
                "name": "Sedia_regista",
                "description": "Sedia regista",
                "supported": false,
                "searchable": true,
                "tenantTypes": []
            }
        ],
        "types": [
            {
                "typeId": "60c73af609e2081fa9b6d42a",
                "name": "Sassi",
                "description": "Sassi",
                "supported": false,
                "tenantTypes": []
            },
            {
                "typeId": "60c73af609e2081fa9b6d42b",
                "name": "Erba_sintetica",
                "description": "Erba sintetica",
                "supported": false,
                "tenantTypes": []
            },
            {
                "typeId": "60c73af609e2081fa9b6d42c",
                "name": "Molo",
                "description": "Molo",
                "supported": false,
                "tenantTypes": []
            },
            {
                "typeId": "60ccb0874107e97fccaac087",
                "name": "Spiaggia",
                "description": "Spiaggia",
                "supported": true,
                "tenantTypes": []
            },
            {
                "typeId": "60ccb0874107e97fccaac088",
                "name": "Erba_naturale",
                "description": "Erba naturale",
                "supported": false,
                "tenantTypes": []
            },
            {
                "typeId": "60ccb0874107e97fccaac089",
                "name": "Ciottoli",
                "description": "Ciottoli",
                "supported": false,
                "tenantTypes": []
            }
        ],
        "targets": [
            {
                "id": "60c73af609e2081fa9b6d42d",
                "name": "Famiglie",
                "description": "Famiglie",
                "supported": true,
                "tenantTypes": []
            },
            {
                "id": "60c73af609e2081fa9b6d42e",
                "name": "Coppie",
                "description": "Coppie",
                "supported": true,
                "tenantTypes": []
            },
            {
                "id": "60c73af609e2081fa9b6d42f",
                "name": "Ragazzi",
                "description": "Ragazzi",
                "supported": false,
                "tenantTypes": []
            }
        ],
        "visible": true,
        "maxNumBookingGuests": 0,
        "numBookablePlaces": 0,
        "maxPlacesPerBooking": 0,
        "withoutLayout": false,
        "lastMinute": true,
        "upfront": false,
        "latitude": 40.8197859,
        "longitude": 14.2113269,
        "order": 1,
        "bookingUserDetailActive": false
    }
],
"pageable": {
    "sort": {
        "sorted": true,
        "unsorted": false,
        "empty": false
    },
    "pageNumber": 0,
    "pageSize": 1,
    "offset": 0,
    "paged": true,
    "unpaged": false
},
"last": true,
"totalElements": 1,
"totalPages": 1,
"sort": {
    "sorted": true,
    "unsorted": false,
    "empty": false
},
"first": true,
"number": 0,
"numberOfElements": 1,
"size": 1,
"empty": false

Data classes generated through the plugin. (I'll just paste this one)

data class User(
@SerializedName("content")
val content: Content? = null,
@SerializedName("empty")
val empty: Boolean? = null,
@SerializedName("first")
val first: Boolean? = null,
@SerializedName("last")
val last: Boolean? = null,
@SerializedName("number")
val number: Int? = null,
@SerializedName("numberOfElements")
val numberOfElements: Int? = null,
@SerializedName("size")
val size: Int? = null,
@SerializedName("totalElements")
val totalElements: Int? = null,
@SerializedName("totalPages")
val totalPages: Int? = null

) : Serializable

Jonathan
  • 203
  • 3
  • 15

1 Answers1

0

You are expecting a type of data that is not provided by the server. Actually, your endpoint returns you a json object while you expect a list of users.

you need to create another data class that holds a list of users.

If you are lost in creating data classes, i encourage you to use JsonToKotlin Android Studio extension to implement them easily.

Baki Kocak
  • 389
  • 1
  • 9