androidjsonkotlinmoshi

Android How to convert this JSON into object of data class with Moshi Kotlin?


There is a Json file which is put to val fileInString: String. This string looks simplistically like this.

{ "groups": 2, "group1": [ { "word": "test11", "description": "desc11" }, { "word": "test12", "description": "desc12" }, ... { "word": "test1n", "description": "desc1n" } ], "group2": [ { "word": "test21", "description": "desc21" }, ... { "word": "test2n", "description": "desc2n" } ] }

I try to convert it by using Moshi in a way below

private lateinit var dictionary: Dictionary
...
        val moshi = Moshi.Builder()
            .addLast(KotlinJsonAdapterFactory())
            .build()
        val adapter: JsonAdapter<Dictionary> = moshi.adapter(Dictionary::class.java)
        this.dictionary = adapter.fromJson(fileInString)!!

where Dictionary is a data class

data class Dictionary(
    val groups: Int,
    val group1: List<WordPair>,
    val group2: List<WordPair>
)

data class WordPair(
    val word: String,
    val description: String
)

It works fine but I'd like more universal solution because the number of groups is going to be increased and I don't want to recompile application every time it happen.

It seems using Map of Map<String, List> look good at the stage. But if I try to implement something like this

data class Dictionary(
    val groups: Int,
    val dict: Map<String, List<WordPair>>
//    val group1: List<WordPair>,
//    val group2: List<WordPair>
)

then I get an error:

"java.lang.RuntimeException: com.squareup.moshi.JsonDataException: Required value 'dict' missing at $"

which is quite fair so there is no any key/value "dict" at json string.

I would expect to get an advise regarding of data class implementation or any possible Moshi settings.. Probably custom deserialization is also a solutiom, I don't know. Thanks!


Solution

  • Reminder, this is not exact resolution of problem

    @JsonAdapter(DirectoryCustomAdapter::class)
    data class Dictionary(
    var groups: Int? = null,
    var dict: MutableMap<String, List<WordPair>> = mutableMapOf()
    )
    data class WordPair(
    val word: String,
    val description: String)
    
    class DirectoryCustomAdapter: JsonDeserializer<Dictionary> {
    override fun deserialize(
        json: JsonElement?,
        typeOfT: Type?,
        context: JsonDeserializationContext?
    ): Dictionary {
        val dictionary: Dictionary = Dictionary()
        json?.let {
            val jsonObject = it.asJsonObject
    
            jsonObject.entrySet().forEach { entry ->
                if (entry.key == "groups") {
                    dictionary.groups = entry.value.asInt
                } else if ((entry.value is Iterable<*>)) {
                    dictionary.dict[entry.key] = (entry.value as Iterable<*>).toList() as List<WordPair>
                }
            }
        }
        return dictionary
    }}