Search code examples
javakotlindata-class

Access function before calling superclass constructor in Kotlin data class


I'm using data classes in Kotlin to significantly reduce the amount of Java code I would otherwise have to write.

However, in one of my Java classes, I'm not sure what to do to achieve the same result in Kotlin.

My Java class looks a bit like this:

public class DataObject {

    private int mId;
    private String mName;

    public DataObject(int id, String name) {
        mId = id;
        mName = name;
    }

    public DataObject(Context context, int id) {
        mId = id;
        Cursor cursor = ...
        cursor.moveToFirst();
        mName = cursor.getString(...);
        cursor.close();
    }

    public int getId() {
        return mId;
    }

    public String getName() {
        return mName;
    }

}

I've tried to rewrite it in Kotlin, and so far I have this:

data class DataObject(val id: Int, val name: String) {

    constructor(context: Context, id: Int) : this(id, fetchName(context))

    private fun fetchName(context: Context): String {
        val cursor = ...
        cursor.moveToFirst()
        val name = cursor.getString(...)
        cursor.close()
        return name
    }

}

But my IDE (Android Studio) is underlining the part where I call fetchName(context) in my constructor in red. It displays the following message:

Cannot access fetchName before superclass constructor has been called

How should I resolve this issue?


Solution

  • You can only use member functions on a fully constructed objects. One way to work around that is to use private extension function or simply a function to fetch name:

    private fun Context.fetchName(): String {
        ///...
        return cursor.getString(1)
    }
    
    data class DataObject(val id: Int, val name: String) {
        constructor(context: Context, id: Int) : this(id, context.fetchName())
    }
    

    Although I do think that using Cursor is a bit too heavy job for constructor. I'd use separate Factory like so:

    data class DataObject(val id: Int, val name: String) {
        object FromCursorFactory {
            fun create(id: Int, context: Context): DataObject {
                val name = context.fetchName()
                return DataObject(id, name)
            }
        }
    }
    

    Further reading: