1

Responses model from Server:

[
  {
    "at1": true,
    "at2": "2021-07-09T08:05:54.307Z",
    "at3": "ANDROID",
  }
]

Actual response: [] Error : com.squareup.moshi.JsonDataException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at path $

interface SomeInterface {
    fun getData(): Single<List<CustomObj>>
}

@Parcelize
data class CustomObj(
    val at1: Boolean,
    val at2: Date,
    val at3: String
) : Parcelable

I tried using @JsonClass(generateAdapter = true), but did not help.

Mapping:

fun toEntities(items: List<ServerResponse>?): List<CustomObj> {
    return items?.mapNotNull { toEntity(it) } ?: listOf()
}

private fun toEntity(item: ServerResponse): CustomObj? {
    return CustomObj(
        at1 = item.smth1 ?: return null,
        at2 = item.smth2 ?: return null,
        at3 = item.smth3 ?: return null
    )
}
MaaAn13
  • 264
  • 5
  • 24
  • 54
  • can you post your code please ? I mean the code of converting the response to Java model – Khalid Taha Jul 12 '21 at 08:37
  • @KhalidTaha Added mapping part – MaaAn13 Jul 12 '21 at 08:47
  • As my experience, it should be Serializable not Parcelable, try the following code using Gson: `List list = new Gson().fromJson(yourJsonResponse, new TypeToken>(){}.getType());` If this works, then it's issue with the way of how you convert the response to java model. – Khalid Taha Jul 12 '21 at 08:54
  • Just to be clear, your server only returns a list of objects right? It isn't like { "fields":[ ] } right? – sinha-shaurya Jul 12 '21 at 08:54
  • @KhalidTaha Parcelize is perfectly fine for this problem. Even auto generating the adapter will work nicely, if the server response is just mapped correctly – sinha-shaurya Jul 12 '21 at 08:55
  • I think there is an issue with the response. We are expecting an Array but the server is sending an Object. Can you add the response from the server here? and in CustomObj val at2: Date it should be string. – Abdul Jul 18 '21 at 19:34

2 Answers2

1

First your json is not a valid json there shouldn't be any , in the end. It should be something like this

[
  {
    "at1": true,
    "at2": "2021-07-09T08:05:54.307Z",
    "at3": "ANDROID"
  }
] 

To create a moshi adapter for the above you need to create a separate type to tell moshi that your json is starting as an array. To handle date attribute you will need to add separate adapter in your moshi.builder. You can use one of the existing Rfc3339DateJsonAdapter adapter that comes with moshi adapter library. DateAdapterUsage

As a part of this answer, I will assume date as a string.


// Assuming Date as string
@JsonClass(generateAdapter = true)
data class CustomObj(
    val at1: Boolean,
    val at2: String,
    val at3: String
)

class Sample {

    private val type = Types.newParameterizedType(List::class.java, CustomObj::class.java)
    private val moshiAdapter: JsonAdapter<List<CustomObj>> = Moshi.Builder().build().adapter(type)

    @Test
    fun `test serialization`() {
        val sampleData =  moshiAdapter.fromJson(yourJsonString) as List<CustomObj>

        println(sampleData)
    }
}

user3354265
  • 777
  • 1
  • 10
  • 26
0

I was able to reproduce the error and here what fixed it: use a custom Adapter:

@JsonClass(generateAdapter = true)
data class CustomObj(
    val at1: Boolean,
    val at2: Date,
    val at3: String
)

@JsonClass(generateAdapter = true)
data class CustomObjJson(
    var at1: Boolean? = null,
    var at2: String? = null,
    var at3: String? = null,
)

class CustomObjAdapter {
    @ToJson
    fun toJson(obj: CustomObj): String {
        return obj.at1.toString() + obj.at2.time.toString() + obj.at3
    }

    @FromJson
    fun fromJson(customObjJson: CustomObjJson): CustomObj {
        var at1 = customObjJson.at1 ?: false
        // TODO: find a way to convert customObjJson.at2 of type String to Date here
        var at2 = Date()
        var at3 = customObjJson.at3
        return CustomObj(at1 = at1, at2 = at2, at3 = at3 ?: "")
    }
}

next use type adapter if you want to convert JSON arrays as the doc says: Moshi Arrays

var type = Types.newParameterizedType(MutableList::class.java, CustomObj::class.java)
var moshi = Moshi.Builder().add(CustomObjAdapter()).build()
var jsonAdapter: JsonAdapter<List<CustomObj>> = moshi.adapter(type)

now you Rock 'n' Roll !!

    val gotcha: List<CustomObj> ? = jsonAdapter.fromJson(JSON_FROM_SERVER) as List<CustomObj>
    println(gotcha)

note: in your gradle file add these:

// at top of file
plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id "org.jetbrains.kotlin.kapt"
}

// dependencies section
implementation "com.squareup.moshi:moshi:1.12.0"
kapt 'com.squareup.moshi:moshi-kotlin-codegen:1.12.0'

and don't forget to clean build ! Cheers Mate !

A.David
  • 172
  • 9