glend
glend

Reputation: 1622

Kotlin: gson conversion "Unable to invoke no-args constructor for class"

I am getting the following error Unable to invoke no-args constructor for class Entry. Registering an InstanceCreator with Gson for this type may fix this problem.

My code extends an Entry class.

abstract class Data : ArrayList<Entry>() {

//code removed for simplicity

    abstract class Entry(str: String) {
        open var name: String = str
    }
}

class Category: Data() {
    class CategoryItem(
        override var name: String
    ) : Entry(name)
}

I have a handler class to handle the transaction.

class JsonHelper(private var type: KClass<Category>) {
    private val json = Gson()
    private var contents: String? = null
    private var data: Any? = null

    fun convert(string: String): Any? {
        data = json.fromJson(string, type.java)
        return data
    }
}

I call

json = JsonHelper(Category::class)
json.convert(file.read())
//file.read() comes from a file as a string, this works as intended

previously I had it setup where Entry was just an empty class and I added the name field while debugging, but it had no effect. I have searched on stackoverflow and haven't found anything that would help, except that you shouldn't use suspend to call it, which you can see im not.

I have also tried using a TypeToken which I would pass into json.fromJson(string, type) at runtime, this also didn't help.

private var type = object: TypeToken<Category>(){}.type

Any Ideas? I would like gson to return a Category type class to me.

Upvotes: 0

Views: 2498

Answers (1)

Alexey Romanov
Alexey Romanov

Reputation: 170815

Well, Category extends ArrayList<Entry>, so GSON needs to know how to instantiate an Entry and it can't because it's abstract.

If the intention is that a Category should only contain CategoryItem, not arbitrary Entry, it should be

abstract class Data<T : Entry> : ArrayList<T>() {

    abstract class Entry(str: String) {
        open var name: String = str
    }
}

class Category: Data<CategoryItem>() {
    class CategoryItem(
        override var name: String = ""
    ) : Entry(name)
}

Extending ArrayList instead of having a field of that type is also not usually a good idea.

Upvotes: 1

Related Questions