AndroidGuy
AndroidGuy

Reputation: 3451

How to serialize ArrayList<float[]> using Moshi JSON library for Android

I'm trying to convert a Java object to JSON using the Moshi library for Android. The object contains a property of type

ArrayList < float[]>

and I'm registering the following adapter to convert the object.

Type type = Types.newParameterizedType
        (List.class, HistoryPath.class, ArrayList.class, Float[].class, Float.class);

JsonAdapter<Drawing> adapter = moshi.adapter(type);

String json = adapter.toJson(drawing);

The "toJson" method fails with the following exception:

java.lang.IllegalArgumentException: Platform java.util.ArrayList annotated [] requires explicit JsonAdapter to be registered at com.squareup.moshi.ClassJsonAdapter$1.create(ClassJsonAdapter.java:50) at com.squareup.moshi.Moshi.adapter(Moshi.java:99) at com.squareup.moshi.ClassJsonAdapter$1.createFieldBindings(ClassJsonAdapter.java:90) at com.squareup.moshi.ClassJsonAdapter$1.create(ClassJsonAdapter.java:74) at com.squareup.moshi.Moshi.adapter(Moshi.java:99) at com.squareup.moshi.ClassJsonAdapter$1.createFieldBindings(ClassJsonAdapter.java:90) at com.squareup.moshi.ClassJsonAdapter$1.create(ClassJsonAdapter.java:74) at com.squareup.moshi.Moshi.adapter(Moshi.java:99) at com.squareup.moshi.Moshi.adapter(Moshi.java:57) at com.squareup.moshi.CollectionJsonAdapter.newArrayListAdapter(CollectionJsonAdapter.java:51) at com.squareup.moshi.CollectionJsonAdapter$1.create(CollectionJsonAdapter.java:35) at com.squareup.moshi.Moshi.adapter(Moshi.java:99) at com.squareup.moshi.Moshi.adapter(Moshi.java:57)

I think my type definitions are wrong but I can't seem to find the right value

Upvotes: 7

Views: 10019

Answers (4)

Patrick
Patrick

Reputation: 1665

You can change ArrayList for MutableList and it works!

Upvotes: 1

norbDEV
norbDEV

Reputation: 5365

Those who want to use ArrayList and Moshi


Solution 1

You have to make adapters for every object you want to use.

class ThingArrayListMoshiAdapter {
    @ToJson
    fun arrayListToJson(list: ArrayList<Thing>): List<Thing> = list

    @FromJson
    fun arrayListFromJson(list: List<Thing>): ArrayList<Thing> = ArrayList(list)
}

usage

Moshi
    .Builder()
    .add(ThingArrayListMoshiAdapter())
    .build()

Solution 2

Make a JsonAdapter for ArrayList, like Moshi's CollectionJsonAdapter

abstract class MoshiArrayListJsonAdapter<C : MutableCollection<T>?, T> private constructor(
    private val elementAdapter: JsonAdapter<T>
) :
    JsonAdapter<C>() {
    abstract fun newCollection(): C

    @Throws(IOException::class)
    override fun fromJson(reader: JsonReader): C {
        val result = newCollection()
        reader.beginArray()
        while (reader.hasNext()) {
            result?.add(elementAdapter.fromJson(reader)!!)
        }
        reader.endArray()
        return result
    }

    @Throws(IOException::class)
    override fun toJson(writer: JsonWriter, value: C?) {
        writer.beginArray()
        for (element in value!!) {
            elementAdapter.toJson(writer, element)
        }
        writer.endArray()
    }

    override fun toString(): String {
        return "$elementAdapter.collection()"
    }

    companion object {
        val FACTORY = Factory { type, annotations, moshi ->
            val rawType = Types.getRawType(type)
            if (annotations.isNotEmpty()) return@Factory null
            if (rawType == ArrayList::class.java) {
                return@Factory newArrayListAdapter<Any>(
                    type,
                    moshi
                ).nullSafe()
            }
            null
        }

        private fun <T> newArrayListAdapter(
            type: Type,
            moshi: Moshi
        ): JsonAdapter<MutableCollection<T>> {
            val elementType =
                Types.collectionElementType(
                    type,
                    MutableCollection::class.java
                )

            val elementAdapter: JsonAdapter<T> = moshi.adapter(elementType)

            return object :
                MoshiArrayListJsonAdapter<MutableCollection<T>, T>(elementAdapter) {
                override fun newCollection(): MutableCollection<T> {
                    return ArrayList()
                }
            }
        }
    }
}

usage

Moshi
    .Builder()
    .add(MoshiArrayListJsonAdapter.FACTORY)
    .build()

Upvotes: 11

Anup Ammanavar
Anup Ammanavar

Reputation: 432

Convert it into an array.

Let's assume you want to use an arraylist : ArrayList<>. You convert it into an array. arraylist.toArray()

Upvotes: 1

Eric Cochran
Eric Cochran

Reputation: 8574

ArrayList is a platform type, as the error says. You can use List (or make a custom JsonAdapter specifically for ArrayList).

Also, there's a problem here: Type type = Types.newParameterizedType(List.class, HistoryPath.class, ArrayList.class, Float[].class, Float.class);

This type is List<HistoryPath, ArrayList, Float[], Float> which is invalid, and it will not yield the correct result for JsonAdapter<Drawing> adapter = moshi.adapter(type);.

You probably just want JsonAdapter<Drawing> adapter = moshi.adapter(Drawing.class);.

Upvotes: 12

Related Questions