Search code examples
androidmoshi

How to serialize SparseArray with Moshi


How can I serialize SparseArray to JSON by Moshi? I really don't understand how to make right adapter for this, any help is appreciated.

EDIT: I've made it work by this code

class SparseArrayJsonAdapter : JsonAdapter<SparseArray<WaterWarningItem>>() {
override fun fromJson(reader: JsonReader?): SparseArray<WaterWarningItem> {
    TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}

override fun toJson(writer: JsonWriter?, value: SparseArray<WaterWarningItem>) {
    writer?.let { writer ->
        writer.beginArray()
        for (i in 0 until value.size()) {
            val key = value.keyAt(i)
            val item = value[key]
            writeWarningItem(writer, item)
        }
        writer.endArray()
        writer.close()
    }
}

fun writeWarningItem(writer: JsonWriter, item: WaterWarningItem) {
    writer.beginObject()
    writer.name("id").value(item.id)
    writer.name("title").value(item.title)
    writer.name("warning_lvl").value(item.warningLvl)
    writer.name("own_limit").value(item.ownLimit)
    writer.endObject()
}

}

I use this adapter like

val a = SparseArrayJsonAdapter()
val json = a.toJson(value)

But I dont't know if this is right way. Adapter are attached by moshi builder in all examples, but it doesn't work with my adapter. Is this ok?


Solution

  • Based on your existing toJson implementation, this is a generic version you can use for serializing your SparseArrays.

    class SparseArrayJsonAdapter(
        private val elementAdapter: JsonAdapter<Any?>) : JsonAdapter<SparseArray<Any?>>() {
      object Factory : JsonAdapter.Factory {
        override fun create(type: Type, annotations: Set<Annotation>,
            moshi: Moshi): JsonAdapter<*>? {
          if (annotations.isNotEmpty()) return null
          val rawType = Types.getRawType(type)
          if (rawType != SparseArray::class.java) return null
          val elementType = (type as ParameterizedType).actualTypeArguments[0]
          return SparseArrayJsonAdapter(moshi.adapter(elementType))
        }
      }
    
      override fun fromJson(reader: JsonReader): SparseArray<Any?> {
        throw UnsupportedOperationException()
      }
    
      override fun toJson(writer: JsonWriter, value: SparseArray<Any?>?) {
        checkNotNull(value, { "Adapter doesn't support null. Wrap with nullSafe()." }).apply {
          writer.beginArray()
          var index = 0
          val size = size()
          while (index < size) {
            elementAdapter.toJson(writer, valueAt(index++))
          }
          writer.endArray()
        }
      }
    }
    
    data class WaterWarningItem(val id: Long, val title: String, val warning_lvl: String,
        val own_limit: String)
    
    fun main(args: Array<String>) {
      val moshi = Moshi.Builder().add(SparseArrayJsonAdapter.Factory).build()
      val adapter = moshi.adapter<SparseArray<WaterWarningItem>>(
          Types.newParameterizedType(SparseArray::class.java, WaterWarningItem::class.java))
      val result = adapter.toJson(SparseArray<WaterWarningItem>(1).apply {
        put(7, WaterWarningItem(5L, "Hello", "Fine", "Okay"))
      })
    }