Search code examples
androidsynchronizationretrofitretrofit2moshi

Not sure how to resolve the issue "com.squareup.moshi.JsonDataException: Expected BEGIN_ARRAY but was STRING at path $"


I am working on an Android app written in Kotlin. I am using Moshi and Retrofit to push and pull some data from a server. In this error, I am pushing data up to the server and expecting a json string response with a "record" for every row if it was successful or not. I am syncing multiple tables this way and one is not working for some reason. Below is comparing Devices (working) with PalletsPicked (throwing this error).

// The Sync Up Call for Devices
val repResult = SyncUpApi.retrofitService.syncUp(
    "devices", _deviceid, _deviceKey, devicesJson
)

// The Sync Up Call for Pallets Picked
val repResult = SyncUpApi.retrofitService.syncUp(
    "pallets_picked", _deviceid, _deviceKey, palletsPickedJson
)

And here is the sync up Api


import com.squabtracker.spoc.entity.SyncUpResponseEntity
import retrofit2.http.*

interface SyncUpApiService {

    @FormUrlEncoded
    @POST("sync_up.php")
    suspend fun syncUp(@Field("table") Table: String,
                         @Field("deviceid") DeviceID: Int,
                         @Field("key") DeviceKey: String,
                         @Field("data") Data: String): List<SyncUpResponseEntity>
}

object SyncUpApi {
    val retrofitService : SyncUpApiService by lazy {
        Network.retrofit.create(SyncUpApiService::class.java) }
}

Here is the structure of the SyncUpResponseEntity

data class SyncUpResponseEntity (

    @ColumnInfo @Json(name= "primary_key")      val PrimaryKey: Long,
    @ColumnInfo @Json(name= "fk_repid")         val fkRepID: Int,
    @ColumnInfo @Json(name= "table_name")       val TableName: String,
    @ColumnInfo @Json(name= "success")          val Success: Int

)

On the server-side the data is accepted clean and before looping through each item an response is created $response = array();

Then during each loop in Devices:

$response[] = array(
            "primary_key" => $item['pk_deviceid'],
            "fk_repid" => $item['fk_repid'],
            "table_name" => "devices",
            "success" => $success);

And in PalletsPicked

$response[] = array(
            "primary_key" => $item['pk_pallets_pickedid'],
            "fk_repid" => $item['fk_repid'],
            "table_name" => "pallets_picked",
            "success" => $success);

Finally before sending back to the device - happens for both Devices and Pallets Picked

echo json_encode($response);

The response from the server for Devices

[{"primary_key":5,"fk_repid":870,"table_name":"devices","success":1}]

And the response for Pallets Picked

[{"primary_key":1009700278,"fk_repid":749,"table_name":"pallets_picked","success":1}]

In Kotlin I have the call to the SyncUpApi wrapped in a try-catch and for PalletsPicked it is erroring out and I am not sure why it works for some like Devices, but not for this one. The inital error was: com.squareup.moshi.JsonEncodingException: Use JsonReader.setLenient(true) to accept malformed JSON at path $ Then after setting this to lenient I got: com.squareup.moshi.JsonDataException: Expected BEGIN_ARRAY but was STRING at path $

If there is any other code that needs to be shown to help out just let me know...

Any help is much appreciated! Thanks!


Solution

  • I found this SO article on how to add logging How can I debug my retrofit API call?

    After adding this as per the accepted answer I was able to see in full detail my call and response. Turns out the PHP was spitting out an undefined index alert before returning the actual json data that I wanted. I fixed this and everything is working now!