Reputation: 34487
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.
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
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
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
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