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

158 views Asked by At

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!

1

There are 1 answers

0
damienG On BEST ANSWER

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
}}