I am implementing Room persistence lib in kotlin for my database implementation.
Following are my Entity
, Dao
and Database
classes:
Food.kt
@Entity
class Food(@ColumnInfo(name = "food_name") var foodName: String,
@ColumnInfo(name = "food_desc") var foodDesc: String,
@ColumnInfo(name = "protein") var protein: Double,
@ColumnInfo(name = "carbs") var carbs: Double,
@ColumnInfo(name = "fat") var fat: Double)
{
@ColumnInfo(name = "id")
@PrimaryKey(autoGenerate = true)
var id: Long = 0
@ColumnInfo(name = "calories")
var calories: Double = 0.toDouble()
}
PersonalizedFood.kt
@Entity(primaryKeys = arrayOf("food_id","date"))
class PersonalizedFood(@ColumnInfo(name = "quantity") var quantity: Int,
@ColumnInfo(name = "unit") var unit: String,
@ColumnInfo(name = "date") var date: Date){
@ColumnInfo(name = "food_id")
var foodId:Long = 0
}
FoodDao.kt
@Dao
interface FoodDao {
companion object{
const val ID = "id"
const val NAME = "name"
const val PROTEIN = "protein"
const val DESC = "desc"
const val CARBS = "carbs"
const val FAT = "fat"
const val DATE = "date"
const val FOOD_ID = "food_id"
const val ALL_FOOD_LIST = "food"
const val PERSONALISED_FOOD_LIST = "personalised_food"
}
/**
* Returns food details of a food given by food_id
*/
@Query("SELECT * FROM $ALL_FOOD_LIST WHERE $ID=:food_id")
fun getFoodDetails(food_id:Long):Food
/**
* Inserts food items in all_food_list
*/
@Insert
fun addFoodList(list:ArrayList<Food>)
@Insert(onConflict = REPLACE)
fun saveFood(food:PersonalizedFood)
@Query("SELECT * FROM $PERSONALISED_FOOD_LIST WHERE $FOOD_ID=:foodId and $DATE=:date")
fun getFood(foodId:Int, data:Date):PersonalizedFood
@Query("SELECT * FROM $ALL_FOOD_LIST where $ID in (select $FOOD_ID from $PERSONALISED_FOOD_LIST where $DATE = :date)")
fun getFood(date:Date):ArrayList<Food>
}
Converter.kt
class Converter {
companion object{
@TypeConverter
fun fromTimestamp(value: Long?): Date? {
return if (value == null) null else Date(value)
}
@TypeConverter
fun dateToTimestamp(date: Date): Long {
return date.time
}
}
}
FoodDatabase.kt
@Database(entities = arrayOf(Food::class, PersonalizedFood::class), version = 1)
@TypeConverters(Converter::class)
abstract class FoodDatabase : RoomDatabase(){
abstract fun foodDao():FoodDao
companion object{
private val databaseName = "diet"
var dbInstance:FoodDao? = null
fun getInstance(context:Context):FoodDao?{
if(dbInstance == null)
dbInstance = Room.inMemoryDatabaseBuilder(context, FoodDatabase::class.java).build().foodDao()
return dbInstance;
}
}
}
And when i run following code to create database:
FoodDatabase.getInstance(baseContext)?.getFood(Calendar.getInstance().time)
It gives me following exception:
Caused by: java.lang.RuntimeException: cannot find implementation for com.chandilsachin.diettracker.database.FoodDatabase. FoodDatabase_Impl does not exist at android.arch.persistence.room.Room.getGeneratedImplementation(Room.java:90) at android.arch.persistence.room.RoomDatabase$Builder.build(RoomDatabase.java:340) at com.chandilsachin.diettracker.database.FoodDatabase$Companion.getInstance(FoodDatabase.kt:21) at com.chandilsachin.diettracker.MainActivity$SetUpFoodDatabase.doInBackground(MainActivity.kt:95) at com.chandilsachin.diettracker.MainActivity$SetUpFoodDatabase.doInBackground(MainActivity.kt:77) at android.os.AsyncTask$2.call(AsyncTask.java:295) at java.util.concurrent.FutureTask.run(FutureTask.java:237) at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) at java.lang.Thread.run(Thread.java:818)
Has anyone implemented room persistence in kotlin?
Edited
This question was marked duplicate of this. Though problem statement is same but solution given does not solve my problem. Solution says i have to add replace annotationProcessor
to kapt "android.arch.persistence.room:compiler:1.0.0-alpha1"
dependency. I made those changes and it resulted in gradle error while project build.
Information:Gradle tasks [:app:assembleDebug] Warning:warning: Supported source version 'RELEASE_7' from annotation processor 'android.arch.persistence.room.RoomProcessor' less than -source '1.8' Warning:warning: The following options were not recognized by any processor: '[kapt.kotlin.generated]' /Users/BBI-M1025/Documents/BBI/Workspace_fun/Android/diet-tracker/app/src/main/java/com/chandilsachin/diettracker/database/Food.kt Error:(1, 1) Some error(s) occurred while processing annotations. Please see the error messages above. Error:Execution failed for task ':app:kaptDebugKotlin'.
Compilation error. See log for more details Information:BUILD FAILED in 10s Information:2 errors Information:2 warnings Information:See complete output in console
I am attaching my gradle file also:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "com.chandilsachin.diettracker"
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.0.1'
compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha8'
compile 'com.android.support:cardview-v7:25.0.1'
compile 'com.android.support:recyclerview-v7:25.0.1'
compile 'com.github.ne1c:rainbowmvp:1.2.1'
compile "org.jetbrains.anko:anko-commons:0.10.0"
/*annotationProcessor "android.arch.persistence.room:compiler:1.0.0-alpha1"
compile "android.arch.lifecycle:extensions:1.0.0-alpha1"
annotationProcessor "android.arch.lifecycle:compiler:1.0.0-alpha1"*/
compile "android.arch.persistence.room:runtime:1.0.0-alpha1"
annotationProcessor "android.arch.persistence.room:compiler:1.0.0-alpha1"
kapt "android.arch.persistence.room:compiler:1.0.0-alpha1"
testCompile 'junit:junit:4.12'
}
repositories {
mavenCentral()
}
Has anyone come across this issue?
The Room persistence library provides an abstraction layer over SQLite to allow fluent database access while harnessing the full power of SQLite. In particular, Room provides the following benefits: Compile-time verification of SQL queries.
The room is an ORM ( Object Relational Mapper ) for SQLite database in Android. It is part of the Architecture Components. The room makes using SQLite much easier for you by implementing annotations.
Room is a persistence library that's part of Android Jetpack. Room is an abstraction layer on top of a SQLite database. SQLite uses a specialized language (SQL) to perform database operations. Instead of using SQLite directly, Room simplifies the chores of setting up, configuring, and interacting with the database.
After spinning my head around for a while with this problem, I came across to the solution.
It was really hard as there is no official tutorial, blog etc out there to help with this problem as of now.
I had to do several hit and trial for all the combination of gradle plugins and dependencies as i knew that something is wrong with gradle config only.
Lets come to the solution:
I had to remove apply plugin: 'kotlin-kapt'
from build.gradle(:module) file
and replace annotationProcessor "android.arch.persistence.room:compiler:1.0.0-alpha1"
to kapt "android.arch.persistence.room:compiler:1.0.0-alpha1"
.
This is the gradle configuration to successfully compile code.
But there more things to check. You have to initialise properties of your @Entity class
unlike java given in Room Persistence lib doc. Though there are getter setter but it is not mentioned to create a constructor with initialisation.
So I had to change my @Entity
class with this:
@Entity(tableName = "all_food_list")
class Food (@ColumnInfo(name = "food_name") var foodName: String = "",
@ColumnInfo(name = "food_desc") var foodDesc: String = "",
@ColumnInfo(name = "protein") var protein: Double = 0.0,
@ColumnInfo(name = "carbs") var carbs: Double = 0.0,
@ColumnInfo(name = "fat") var fat: Double = 0.0,
@ColumnInfo(name = "calories") var calories: Double = 0.0)
{
@ColumnInfo(name = "id")
@PrimaryKey(autoGenerate = true)
var id: Long = 0
}
Now for TypeConverts, Unlike java, you need to create normal function not static functions(companion object):
class Converters{
@TypeConverter
fun fromTimestamp(value: String): Calendar {
val arr = value.split("-")
val cal = Calendar.getInstance()
cal.set(arr[0].toInt(), arr[1].toInt(), arr[2].toInt())
return cal
}
@TypeConverter
fun dateToTimestamp(date: Calendar): String {
return "${date.get(Calendar.DATE)}-${date.get(Calendar.MONTH)+1}-${date.get(Calendar.YEAR)}"
}
}
I am adding build.gradle file also to make it more clear:
build.gradle(:project)
buildscript {
ext.kotlin_version = '1.1.2-4'
ext.gradle_version_stable = '2.3.2'
ext.gradle_version_preview = '3.0.0-alpha1'
ext.anko_version = '0.10.0'
repositories {
maven { url 'https://maven.google.com' }
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0-alpha1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
maven { url 'https://maven.google.com' }
jcenter()
maven { url "https://jitpack.io" }
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
build.gradle(:module)
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "com.chandilsachin.diettracker"
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"
...
...
// room persistence dependency
compile "android.arch.persistence.room:runtime:1.0.0-alpha1"
kapt "android.arch.persistence.room:compiler:1.0.0-alpha1"
testCompile 'junit:junit:4.12'
}
repositories {
mavenCentral()
}
I think this is all, I did to make my code woking.
Hope this helps someone else also.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With