N Sharma
N Sharma

Reputation: 34487

Type mismatch. Required Map<String, Any> Found Map<String, Any?>

I am trying to execute select using anko extension in kotlin like below

fun read() {
    database.use {
        select(PersonTable.Name).exec {
            select("myTable").exec() {
                parseList(
                    object : MapRowParser<Map<String, Any>> {
                        override fun parseRow(columns: Map<String, Any?>): Map<String, Any> {
                            Log.d("Hello", "Hello")
                            return columns;
                        }
                    }
                )
            }
        }
    }
}

I am getting an error on return column

Type mismatch. Required Map<String, Any> Found Map<String, Any?>

If I change to override fun parseRow(columns: Map<String, Any>): Map<String, Any> then it shows an error.

enter image description here

build.gradle

apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.2"
    defaultConfig {
        applicationId "com.williams.fourthdemo"
        minSdkVersion 16
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
    compile 'com.android.support:appcompat-v7:25.3.1'
    testCompile 'junit:junit:4.12'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    compile "org.jetbrains.anko:anko-common:0.10.1"
    compile "org.jetbrains.anko:anko-sqlite:0.10.1"
}

Is this bug in the anko library ?

Upvotes: 1

Views: 6504

Answers (3)

hasen
hasen

Reputation: 166122

It's not a bug in Anko. It's a bug in your code.

This function is wrong:

override fun parseRow(columns: Map<String, Any?>): Map<String, Any> {
    Log.d("Hello", "Hello")
    return columns;
}

You are taking an input and returning it as-is but with a different type.

Your input is of type Map<String, Any?> but you have to somehow transform it into Map<String, Any>

It would be as if you defined a function that takes String and returns Int like this:

fun parseString(s: String): Int {
    return s
}

This will obviously not compile.

The interface you're trying to implement is basically:

interface MapRowParser<out T> {
    fun parseRow(columns: Map<String, Any?>): T
}

You're supposed to provide a function that converts a dictionary representing a database row, to some concrete object of your choosing. But you have to actually provide code to do the processing.

Alternatively, Anko provides you a function that can automagically match a table row to a class constructor, which is what I would prefer to use, instead of doing a manual mapping of dictionary keys to class fields.

data class User(val userId: Int, val userName: String)
val rowParser = classParser<User>()

Upvotes: 1

Ryba
Ryba

Reputation: 1299

Looks like

object : MapRowParser<Map<String, Any>> {

should really be

object : MapRowParser<Map<String, Any?>> {

It is very common for databases to have columns that return a null in the cell. The way you defined it as Any means null is never going to happen. If you cast your return to a Map<String, Any> then you will simply end up with runtime errors happening if a null is contained anywhere.

You are best suited by making it an Any? type which forces the parseRow return type to be Map<String, Any?> as well and fixes the potential bug in your code that would happen if a null value were to creep up somewhere.

Upvotes: 3

Miha_x64
Miha_x64

Reputation: 6363

columns has type Map<String, Any?>, note that Any? is whatever object or null. But method's return type is Map<String, Any>, Any can't be null.

For example, you may filter incoming map, leaving only non-null values: columns.filterValues { it != null } as Map<String, Any>. It contains an unchecked cast, but it's safe.

Upvotes: 2

Related Questions