JSON Serialization / Deserialization Kotlin Android Jetpack Compose Table

1.8k Views Asked by At

I'm in the process of creating a table section in Jetpack Compose that deserializes the data from a JSON.

At this point, I'm simply trying to display the data (the table formatting and clean up will come later, so you can ignore that part). Things have been going okay until I got to a part where the table row values are an array of arrays. I'm getting this error:

Error:

Expected class kotlinx.serialization.json.JsonObject as the serialized body of ...TableRow, but had class kotlinx.serialization.json.JsonArray

Here is the part of the test JSON that is being parsed for this table:

{
 "title": "TRANSACTION HISTORY",
 "type": "Table",
 "names": [
      "Date",
      "Amount",
      "Lender",
      "Borrower"
   ],
    "values": [
        [
           "07\/01\/2014",
           "$315,000",
           "Steve's Lending Co.",
           "Glenn Danzig"
         ],
         [
           "10\/13\/2011",
           "$236,000",
           "Feet Company",
           "Marcus Toeswater"
         ]
      ]
   },
   {
     "title": "ASSESSMENT & TAX",
     "type": "Table",
     "names": [
          "Year",
          "Property Taxes",
          "Tax Assessment"
     ],
     "values": [
          [
            "2017",
            "$6,068",
            "$395,000"
          ],
          [
            "2016",
            "$5,864",
            "$372,000"
          ],
          [
            "2015",
            "$5,609",
            "$341,500"
          ]
      ]
   },

Here's the code I have right now. I'm simply trying to post two rows of data: 1 with the column header names, and 1 with all of the row data (doesn't have to look nice at this point - I'm just trying to get the mapping done)

@Serializable
@SerialName("Table")
@Parcelize
data class TableSection(
    override val title: String? = null,
    @SerialName("names")
    val columnHeader: ArrayList<String?> = arrayListOf(),
    @SerialName("values")
    val tableData: ArrayList<TableRow> = arrayListOf(),
) : Section() {
    @Composable
    override fun Content(modifier: Modifier) {
        return Column {
            Row {
                columnHeader.map {
                    Text(it ?: "")
                }
            }
            Row {
                tableData.map { row ->
                    row.tableRowValues.map { value ->
                        Text(value ?: "")
                    }
                }
            }
        }
    }
}

@Serializable
@Parcelize
data class TableRow(
    @Serializable
    val tableRowValues: ArrayList<String?> = arrayListOf(),
) : Parcelable

Note: The Title and the Table Column Headers work just fine. It's the table data that is throwing the error.

1

There are 1 best solutions below

0
On BEST ANSWER

I ended up creating a custom serializer to get the nested values:

@Serializable(with = TableRowSerializer::class)
@Parcelize
data class TableRow(
    val tableRowValues: List<String?> = arrayListOf(),
) : Parcelable

object TableRowSerializer : KSerializer<TableRow> {
    private val serializer = ListSerializer(String.serializer())

    override val descriptor: SerialDescriptor = serializer.descriptor

    override fun serialize(encoder: Encoder, value: TableRow) {
        val rowValues = value.tableRowValues
            rowValues.let{rowValues as? List<String>}
                ?.let { encoder.encodeSerializableValue(serializer, it) }
    }

    override fun deserialize(decoder: Decoder): TableRow {
        return TableRow(decoder.decodeSerializableValue(serializer))
    }
}