Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

moshi

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

like image 475
AndroidGuy Avatar asked May 08 '17 16:05

AndroidGuy


People also ask

What is Moshi in Android?

Moshi is a modern JSON library for Android and Java from Square. It can be considered as the successor to GSON, with a simpler and leaner API and an architecture enabling better performance through the use of the Okio library.

What is the purpose of Moshi library?

Moshi is a modern JSON library for Android, Java and Kotlin. It makes it easy to parse JSON into Java and Kotlin classes: Note: The Kotlin examples of this README assume use of either Kotlin code gen or KotlinJsonAdapterFactory for reflection.


2 Answers

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);.

like image 60
Eric Cochran Avatar answered Sep 23 '22 05:09

Eric Cochran


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()
like image 24
norbDEV Avatar answered Sep 22 '22 05:09

norbDEV