Kapt Annotation processors must be explicitly declared now - android

I'm trying to develop a Kotlin AnnotationProcessor library, and I can't figure why I get this error:
Error:Execution failed for task ':app:javaPreCompileDebug'.
> Annotation processors must be explicitly declared now. The following dependencies on the compile classpath are found to contain annotation processor. Please add them to the annotationProcessor configuration.
- compiler.jar (project :compiler)
Alternatively, set android.defaultConfig.javaCompileOptions.annotationProcessorOptions.includeCompileClasspath = true to continue with previous behavior. Note that this option is deprecated and will be removed in the future.
See https://developer.android.com/r/tools/annotation-processor-error-message.html for more details.
I know that as mentionned I could use includeCompileClasspath = true and I tried it and it works fine. But as mentionned, it's deprecated, soon removed, and it is expected to be used for libraries you don't use according to android doc.
So I'm looking for a cleaner solution.
App module
Hello.kt
#HelloGenerated
class Hello(){
override fun showLog() {
Log.i(Hello::class.simpleName, "${Gahfy_Hello().getName()}")
}
}
Build.gradle
dependencies{
kapt project(":compiler")
compileOnly project(":compiler")
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
}
Compiler module
HelloGenerated.kt
#Target(AnnotationTarget.CLASS)
#Retention(AnnotationRetention.SOURCE)
annotation class HelloGenerated
I also tried without Target and Retention and have same issue
HelloGenerator.kt
#SupportedAnnotationTypes("net.gahfy.HelloGenerated")
class HelloGeneratedInjectorProcessor: AbstractProcessor() {
override fun getSupportedAnnotationTypes(): MutableSet<String> {
return mutableSetOf(HelloGenerated::class.java.name)
}
override fun getSupportedSourceVersion(): SourceVersion {
return SourceVersion.latest()
}
override fun process(annotations: MutableSet<out TypeElement>, roundEnv: RoundEnvironment): Boolean {
val annotation = annotations.firstOrNull { it.toString() == "net.gahfy.HelloGenerated" } ?: return false
for (element in roundEnv.getElementsAnnotatedWith(annotation)) {
val className = element.simpleName.toString()
val `package` = processingEnv.elementUtils.getPackageOf(element).toString()
generateClass(className, `package`)
}
return true
}
private fun generateClass(className: String, `package`: String) {
val kotlinGeneratedPath = (processingEnv.options["kapt.kotlin.generated"] as String).replace("kaptKotlin", "kapt")
val kaptKotlinGenerated = File(kotlinGeneratedPath)
val source = "package $`package`\n\nclass Lachazette_$className(){fun getName():String{return \"World\"}}"
val relativePath = `package`.replace('.', File.separatorChar)
val folder = File(kaptKotlinGenerated, relativePath).apply { if(!exists()){mkdirs()} }
File(folder, "Lachazette_$className.kt").writeText(source)
}
companion object {
const val KAPT_KOTLIN_GENERATED_OPTION_NAME = "kapt.kotlin.generated"
}
}
build.gradle
apply plugin: 'java-library'
apply plugin: 'kotlin'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
}
sourceCompatibility = "1.7"
targetCompatibility = "1.7"
resources/META-INF/services/javax.annotation.processing.Processor
net.gahfy.HelloGenerator
I'm now looking for a cleaner solution than just includeCompileClasspath = true.
Some information:
kapt works well, I'm using it with Dagger and BindingAdapter without any problem
My annotation processor is well processed when building, and the message in the log is the good one when I set includeCompileClasspath = true
Thank you very much

Not sure if this is 100% related to your problem but I had the same error after moving auto-value to kapt. I solved it by declaring the auto-value dependency as both kapt and annotationProcessor.
So in your case:
dependencies{
kapt project(":compiler")
annotationProcessor project(":compiler")
compileOnly project(":compiler")
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
}

Related

iOS dependences not resolving in Kotlin MultiPlatform Project

I am trying to develop a small library to post issues to my company's Jira server, and I thought that a Kotlin MPP w/ KTOR would be just the ticket.
At first, following a few tutorials, I made a shared project, and the imports for iOS were working fine but Android's Ktor implementation would not resolve. Then I realized that I needed to recreate the project and create a library instead of a shared application, as I have existing codebases for each mobile client already, and I need to publish the MPP library to be used by them.
Upon recreating the project as a library, and simply starting to add the dependencies for KTOR 1.3.2, the iOS dependencies are failing to resolve. This is not just KTOR, it is any iOS dependency, so there's obviously something incorrect in my project setup, but I am unable to spot it.
Here is the gradle file:
plugins {
id 'org.jetbrains.kotlin.multiplatform' version '1.3.72'
}
repositories {
jcenter()
mavenCentral()
maven { url "https://kotlin.bintray.com/kotlinx" }
}
group 'com.example.issuereporter'
version '0.0.1'
apply plugin: 'maven-publish'
kotlin {
targets {
final def iOSTarget = System.getenv('SDK_NAME')?.startsWith("iphoneos") ? presets.iosArm64 : presets.iosX64
fromPreset(iOSTarget, 'ios') {
binaries {
framework('IssueReporter')
}
}
fromPreset(presets.jvm, 'android')
}
def ktor_version = "1.3.2"
sourceSets["commonMain"].dependencies {
implementation kotlin('stdlib-common')
implementation "io.ktor:ktor-client-core:$ktor_version"
implementation "io.ktor:ktor-client-json:$ktor_version"
implementation "io.ktor:ktor-client-serialization:$ktor_version"
}
sourceSets["commonTest"].dependencies {
implementation kotlin('test-common')
implementation kotlin('test-annotations-common')
}
sourceSets["androidMain"].dependencies {
implementation kotlin('stdlib')
implementation "io.ktor:ktor-client-core-jvm:$ktor_version"
implementation "io.ktor:ktor-client-json-jvm:$ktor_version"
implementation "io.ktor:ktor-client-serialization-jvm:$ktor_version"
implementation "io.ktor:ktor-client-auth-jvm:$ktor_version"
}
sourceSets["androidTest"].dependencies {
implementation kotlin('test')
implementation kotlin('test-junit')
}
sourceSets["iosMain"].dependencies {
implementation "io.ktor:ktor-client-ios:$ktor_version"
implementation "io.ktor:ktor-client-core-native:$ktor_version"
implementation "io.ktor:ktor-client-json-native:$ktor_version"
implementation "io.ktor:ktor-client-serialization-native:$ktor_version"
}
}
configurations {
compileClasspath
}
task packForXcode(type: Sync) {
final File frameworkDir = new File(buildDir, "xcode-frameworks")
final String mode = project.findProperty("XCODE_CONFIGURATION")?.toUpperCase() ?: 'DEBUG'
final def framework = kotlin.targets.ios.binaries.getFramework("IssueReporter", mode)
inputs.property "mode", mode
dependsOn framework.linkTask
from { framework.outputFile.parentFile }
into frameworkDir
doLast {
new File(frameworkDir, 'gradlew').with {
text = "#!/bin/bash\nexport 'JAVA_HOME=${System.getProperty("java.home")}'\ncd '${rootProject.rootDir}'\n./gradlew \$#\n"
setExecutable(true)
}
}
}
tasks.build.dependsOn packForXcode
The console output is
Could not resolve io.ktor:ktor-client-ios:1.3.2.
Could not resolve io.ktor:ktor-client-core-native:1.3.2.
Could not resolve io.ktor:ktor-client-json-native:1.3.2.
Could not resolve io.ktor:ktor-client-serialization-native:1.3.2.
Anything obvious that I am missing here?
UPDATE
I scrapped and recreated the project w/ an updated version of IntelliJ (IntelliJ IDEA 2019.3.5 (Community Edition)) & the Kotlin 1.4.0 Plugin installed. This gave me a slightly different creation wizard, and the option to use Kotlin as the Gradle syntax.
Updated build.gradle.kts file:
plugins {
kotlin("multiplatform") version "1.4.0"
kotlin("plugin.serialization") version "1.4.0"
id("com.android.library")
id("kotlin-android-extensions")
}
group = "com.example.issuereporter"
version = "1.0-SNAPSHOT"
repositories {
gradlePluginPortal()
google()
jcenter()
mavenCentral()
maven(url = "https://kotlin.bintray.com/kotlinx")
maven(url = "https://dl.bintray.com/kotlin/ktor")
maven(url = "https://repo1.maven.org/maven2/")
maven(url = "https://dl.bintray.com/kotlin/kotlin-eap")
maven(url = "https://plugins.gradle.org/m2/")
}
kotlin {
android()
iosX64("ios") {
binaries {
framework {
baseName = "library"
}
}
}
val ktor_version = "1.3.2"
val serialization_version = "0.20.0"
sourceSets {
val commonMain by getting {
dependencies {
implementation("io.ktor:ktor-client-core:$ktor_version")
implementation("io.ktor:ktor-client-json:$ktor_version")
implementation("io.ktor:ktor-client-serialization:$ktor_version")
implementation("io.ktor:ktor-client-auth:$ktor_version")
implementation("io.ktor:ktor-client-apache:$ktor_version")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:$serialization_version")
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))
}
}
val androidMain by getting {
dependencies {
implementation("androidx.core:core-ktx:1.2.0")
implementation("io.ktor:ktor-client-android:$ktor_version")
implementation("io.ktor:ktor-client-auth-jvm:$ktor_version")
implementation("io.ktor:ktor-client-json-jvm:$ktor_version")
}
}
val androidTest by getting
val iosMain by getting {
dependencies {
implementation("io.ktor:ktor-client-ios:$ktor_version")
implementation ("io.ktor:ktor-client-core-native:$ktor_version")
implementation("io.ktor:ktor-client-json-native:$ktor_version")
implementation("io.ktor:ktor-client-auth-native:$ktor_version")
}
}
val iosTest by getting
}
}
android {
compileSdkVersion(29)
defaultConfig {
minSdkVersion(24)
targetSdkVersion(29)
versionCode = 1
versionName = "1.0"
}
buildTypes {
getByName("release") {
isMinifyEnabled = false
}
}
}
The gradle dependencies for iOS successfully sync when I set the ktor_version to 1.3.2 but not for 1.4.0 (assuming the mirrors haven't updated for the native files??)... but the imports don't compile when I attempt to utilize the class at all... see attached image:
I would guess you don't have enableFeaturePreview("GRADLE_METADATA") in settings.gradle.
settings.gradle
Check our starter project KaMPKit for a running example on 1.3.72. We'll probably bump that to 1.4.0 this week, but for now it should be a good reference.
Here are my dependencies (I have separate iOS targets, but it should still help you):
iosEmulatorMain.dependencies {
implementation "io.ktor:ktor-client-ios:$ktorVersion"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-native:$coroutinesVersion"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-native:$serializationVersion"
implementation "com.soywiz.korlibs.klock:klock-iosx64:$klockVersion"
implementation "com.github.aakira:napier-iosX64:$napierVersion"
}
iosDeviceMain.dependencies {
implementation "io.ktor:ktor-client-ios:$ktorVersion"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-native:$coroutinesVersion"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-native:$serializationVersion"
implementation "com.soywiz.korlibs.klock:klock-iosarm64:$klockVersion"
implementation "com.github.aakira:napier-iosArm64:$napierVersion"
}
Versions:
ktorVersion=1.3.2
Repositories:
maven(url = "https://kotlin.bintray.com/kotlinx")
maven(url = "https://dl.bintray.com/kotlin/ktor")
maven(url = "https://repo1.maven.org/maven2/")
maven(url = "https://dl.bintray.com/kotlin/kotlin-eap")
maven(url = "https://plugins.gradle.org/m2/")
To configure client serializer try to write it like this:
install(JsonFeature) {
serializer = KotlinxSerializer(kotlinx.serialization.json.Json {
ignoreUnknownKeys = true
})
}

Integrate Library module built with Kotlin Coroutines dependency issue

I am building a library module that using coroutines.
My library do the following:
get config from the app module
create a fragment that implemented CoroutineScope (ContentListingFragment)
ContentListingFragment handle all it's process fetching data from the network and show them
from the app module:
We should able to get an instance from the ContentListingFragment and add it to a container
The issue: when I am building the app, I am getting the following error:
Supertypes of the following classes cannot be resolved. Please make sure you have the required dependencies in the classpath:
class nabed.apps.nabedutilslibrary.ui.base.ContentListingFragment, unresolved supertypes: kotlinx.coroutines.CoroutineScope
below is the library module build.gradle
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: "kotlin-kapt"
apply plugin: 'androidx.navigation.safeargs'
android {
compileSdkVersion 28
buildToolsVersion "29.0.0"
defaultConfig {
minSdkVersion 21
targetSdkVersion 28
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
kotlinOptions {
jvmTarget = "1.8"
}
}
}
androidExtensions{
experimental = true
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
// Navigation
implementation "android.arch.navigation:navigation-fragment:$navigation_version"
implementation "android.arch.navigation:navigation-ui:$navigation_version"
implementation "android.arch.navigation:navigation-fragment-ktx:$navigation_version"
implementation "android.arch.navigation:navigation-ui-ktx:$navigation_version"
//Kotlin Coroutines
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.0"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.0-RC1"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
How to handle this without changes on the app module?
You have to change the dependencies declaration in your library's build.gradle:
//Kotlin Coroutines
api "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.0"
api "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.0-RC1"
api keyword will expose these dependencies to the app module
****put this code in build.gradel file in dependencies block and click on sync****
//Kotlin Coroutines
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0"
If you are not going to use Coroutines in the app module but would like to use it in the library, decision with api dependencies not the best one. In this way your app module will be also dependent on Coroutines.
I think, better to remove CoroutineScope implementation from ContentListingFragment and create CoroutineScope object as a ContentListingFragment member.
class ContentListingFragment : Fragment() {
private val job = Job()
private val coroutineScope = object : CoroutineScope {
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.IO
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
coroutineScope.launch { ... }
}
override fun onDestroyView() {
super.onDestroy()
job.cancelChildren()
}
}
Also, LifecycleScope form lifecycle-runtime-ktx may be a the easiest solution. It will remove CoroutineScope creation boilerplate code.
class ContentListingFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewLifecycleOwner.lifecycleScope.launch { ... }
}
}

How to get LiveData from Room?

I'm trying to get LiveData from Room. So my RecycleView can have Live updates if anything in database is changed
I have tried with out LiveData and that works, but when i add LiveData that always shows this error.
error: Not sure how to convert a Cursor to this method's return type (androidx.lifecycle.LiveData<java.util.List<com.example.models.Club>>).
public abstract java.lang.Object getAll(#org.jetbrains.annotations.NotNull()
I googled and looked on this site for solution, but every on with this issue have used rxjava, rxandroid, rxkotlin or ArrayList.
And for them solution is to replace ArrayList with List, and for RX to try coroutine.
Well i am using Coroutine and List and still no progress.
This is my ClubDao
ClubDao
#Query("SELECT * FROM club")
suspend fun getAll(): LiveData<List<Club>>
In Club i have this attributes
Club
#Entity
data class Club(#PrimaryKey var id: Int,
#ColumnInfo(name = "logo_url") var logoUrl: String,
#ColumnInfo(name = "name") var name: String,
#ColumnInfo(name = "town") var town: String,
#ColumnInfo(name = "address") var address: String,
#ColumnInfo(name = "contact_name") var contactName: String,
#ColumnInfo(name = "phone_numbers") var phoneNumbers: String,
#ColumnInfo(name = "email") var email: String)
phoneNumbers should be List, but i convert those to and from json with TypeConverters
TypeConverter is here
TypeConverter
class ConvertersDB {
#TypeConverter
fun fromString(value: String): ArrayList<String> {
val listType = object : TypeToken<ArrayList<String>>() {
}.type
return Gson().fromJson(value, listType)
}
#TypeConverter
fun fromArrayList(list: ArrayList<String>): String {
val gson = Gson()
return gson.toJson(list)
}
}
And my DB
DataBase
#Database(entities = [Club::class], version = 1, exportSchema = false)
#TypeConverters(ConvertersDB::class)
abstract class AppDatabase : RoomDatabase() {
abstract fun clubDao(): ClubDao
companion object {
#Volatile
private var instance: AppDatabase? = null
private val LOCK = Any()
operator fun invoke(context: Context) = instance ?: synchronized(LOCK) {
instance ?: buildDatabase(context).also { instance = it }
}
private fun buildDatabase(context: Context) = Room.databaseBuilder(context,
AppDatabase::class.java, "pss.db")
.allowMainThreadQueries()
.build()
}
}
In my fragment i need to observe all the clubs from database via ViewModel and Repository and send them to RecycleView
Now i am getting error:
error: Not sure how to convert a Cursor to this method's return type (androidx.lifecycle.LiveData<java.util.List<com.example.models.Club>>).
public abstract java.lang.Object getAll(#org.jetbrains.annotations.NotNull()
Does anyone know solution for this?
EDIT:
Gradle
apply plugin: 'com.android.application'
apply plugin: 'androidx.navigation.safeargs'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.overswayit.plesnisavezsrbije"
minSdkVersion 24
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
dataBinding {
enabled true
}
packagingOptions {
exclude 'META-INF/atomicfu.kotlin_module'
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.31"
implementation 'com.jakewharton:butterknife:10.1.0'
implementation 'com.google.android.material:material:1.1.0-alpha07'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.appcompat:appcompat:1.1.0-beta01'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
// Room components
implementation "androidx.room:room-runtime:$rootProject.roomVersion"
implementation "androidx.room:room-ktx:$rootProject.roomVersion"
kapt "androidx.room:room-compiler:$rootProject.roomVersion"
androidTestImplementation "androidx.room:room-testing:$rootProject.roomVersion"
// Room and RxJava
implementation "androidx.room:room-rxjava2:$rootProject.roomVersion"
// Lifecycle components
implementation "androidx.lifecycle:lifecycle-extensions:$rootProject.archLifecycleVersion"
kapt "androidx.lifecycle:lifecycle-compiler:$rootProject.archLifecycleVersion"
androidTestImplementation "androidx.arch.core:core-testing:$rootProject.androidxArchVersion"
// ViewModel Kotlin support
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$rootProject.archLifecycleVersion"
//LiveData Kotlin
implementation "androidx.lifecycle:lifecycle-livedata:$rootProject.archLifecycleVersion"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$rootProject.archLifecycleVersion"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$rootProject.archLifecycleVersion"
// Coroutines
api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$rootProject.coroutines"
api "org.jetbrains.kotlinx:kotlinx-coroutines-android:$rootProject.coroutines"
//RxJava
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
implementation "io.reactivex.rxjava2:rxjava:2.2.6"
implementation 'com.jakewharton.rxbinding3:rxbinding:3.0.0-alpha2'
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.3.31"
annotationProcessor 'com.jakewharton:butterknife-compiler:10.1.0'
implementation 'com.squareup.picasso:picasso:2.71828'
implementation 'com.kaopiz:kprogresshud:1.0.5'
implementation 'com.squareup:otto:1.3.8'
implementation 'agency.tango.android:avatar-view:0.0.2'
implementation 'agency.tango.android:avatar-view-picasso:0.0.2'
implementation 'com.mikhaellopez:circularimageview:3.2.0'
implementation 'com.googlecode.libphonenumber:libphonenumber:8.1.0'
// Data Binding
kapt "com.android.databinding:compiler:3.1.4"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation project(path: ':tuple')
// Navigation Component
implementation 'androidx.navigation:navigation-fragment-ktx:2.0.0'
implementation 'androidx.navigation:navigation-ui-ktx:2.0.0'
//Gson
implementation 'com.google.code.gson:gson:2.8.5'
}
kapt {
generateStubs = true
}
Top Level Gradle
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.31"
classpath "android.arch.navigation:navigation-safe-args-gradle-plugin:1.0.0"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
ext {
roomVersion = '2.1.0'
archLifecycleVersion = '2.2.0-alpha01'
androidxArchVersion = '2.0.0'
coroutines = '1.2.0'
}
As mentioned in the comments, remove suspend.
When a method returns an observable, there is no reason to make it suspend since it just returns and object, does not run any query until it is observed.
#Query("SELECT * FROM club")
fun getAll(): LiveData<List<Club>>
Room's coroutines integration brings ability to return suspend values but when the value itself is asnyc, there is no reason to use it.
I found a good solution to the problem with using rxJava with room and livedata.
The approach is similar to using Retrofit with RxJava, using LiveDataReactiveStreams, which
by default uses flowable.
In your approach i would recomend is:
#Query("SELECT * FROM club")
suspend fun getAll(): LiveData<List<Club>>
changed to
DAO:
#Query("SELECT * FROM club")
fun getAll(): (Any rxJava object) Flowable<List<Club>>
Repository:
fun getAllClubs() : LiveData<List<Club>>{
return LiveDataReactiveStreams.fromPublisher(dao.getAll()"do any transformation or
other functionality you want and then if using Maybe for example transform to
flowable by .toFlowable()")
}
ViewModel:
val clubList : MediatorLiveData<List<Club>>()
fun setClubData(){
clubList.addSource(repository.getAllClubs(), {
clubList.value = it
})
}
then you can observe the livedata object as usual in your view.
Hope what i wrote is understandable, if not i will try to make it better :)

java.lang.NoClassDefFoundError: android.databinding.DataBinderMapperImpl when running Espresso tests

Data binding setup:
apply plugin: 'kotlin-kapt'
android {
dataBinding {
enabled = true
}
}
dependencies {
kapt "com.android.databinding:compiler:3.1.0"
}
The fragment class which uses data binding:
class LandingFragment : Fragment(), Injectable {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val dataBinding = LandingFragmentBinding.inflate(inflater, container, false)
return dataBinding.root
}
}
Every time the Espresso test is run for this fragment, I get the following exception:
java.lang.NoClassDefFoundError: android.databinding.DataBinderMapperImpl
at android.databinding.DataBindingUtil.<clinit>(DataBindingUtil.java:32)
at com.sc.databinding.LandingFragmentBinding.inflate(LandingFragmentBinding.java:42)
at com.sc.ui.landing.LandingFragment.onCreateView(LandingFragment.kt:32)
...
A bit late, but I resolved this issue by adding DataBinding compiler with kapt as a test dependency:
kaptAndroidTest 'androidx.databinding:databinding-compiler:3.3.2'
Or the version not from AndroidX if your project is not using Jetpack yet.
Add
kaptTest "androidx.databinding:databinding-compiler:+"
to dependencies on build.gradle files of all your modules.
I run into this very error. I did 2 things:
1. Added kaptAndroidTest 'androidx.databinding:databinding-compiler:3.5.1' in gradle
2. Used the databinding, that is to say, I create a fake bool variable and injected it for real in a view. It would seem that you cannot just use databinding for retrieving the views instead of issuing the dreaded findViewById. You have to use it at least once in your module. Once you use it you are fine for all the other classes in your module.
I have the same this issue, and fixed by adding
kapt {
generateStubs = true
}
in build.gradle app (all module if using dataBinding)
apply plugin: 'kotlin-kapt'
android {
...
dataBinding {
enabled = true
}
}
kapt {
generateStubs = true
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
...
implementation "androidx.core:core-ktx:+"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
kapt "com.android.databinding:compiler:$android_plugin_version"
}
In build.gradle project
buildscript {
ext.kotlin_version = '1.3.70'
ext.android_plugin_version = '3.5.2'
repositories {
google()
jcenter()
}
dependencies {
classpath "com.android.tools.build:gradle:$android_plugin_version"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
Add dataBinding = true to android { } in your build.gradle file, and everything will be fine, hope this help..
build.gradle:
android {
// skip ..
buildFeatures {
//noinspection DataBindingWithoutKapt
dataBinding = true
viewBinding true
}
// skip ..
}
Try to add the android-apt plugin as per this stackoverflow answer:
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'

Room Persistence lib implementation in Kotlin

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?
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.
Here my gradle files, i didn't need to add thoses plugins.
build.gradle(project):
buildscript {
ext.kotlin_version = '1.1.2-4'
ext.lifecycle_version = '1.0.0-alpha1'
ext.room_version = '1.0.0-alpha1'
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
build.gradle (app)
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
//enable anotation processing with kotlin, disabled by default
kapt {
generateStubs = true
}
android {
/**
...
**/
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
//kotlin
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
//support
compile 'com.android.support:appcompat-v7:25.3.1'
//google architecture
compile "android.arch.lifecycle:runtime:$lifecycle_version"
compile "android.arch.lifecycle:extensions:$lifecycle_version"
annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version"
kapt "android.arch.lifecycle:compiler:$lifecycle_version"
//database
compile "android.arch.persistence.room:runtime:$room_version"
annotationProcessor "android.arch.persistence.room:compiler:$room_version"
kapt "android.arch.persistence.room:compiler:$room_version"
}
repositories {
mavenCentral()
}
Then run menu build-> make project to create impl class.
Hope this helps
I made an example similar using Java and used to have same problem and solution was add APT line apt "android.arch.persistence.room:compiler:1.0.0-alpha1"
without apply: apply plugin: 'kotlin-kapt'. Remove this line!!
You have to clear project and rebuild it before run again and try uninstall existing app on phone or Virtual device.
Hope you help.
I got the same issue when I try to migrate from Java to Kotlin:
RuntimeException: cannot find implementation for AppDatabase. AppDatabase_Impl does not exist
I tried all these answers in this question, none all them works, then I found an article: Kotlinlang Tutorials - Android Frameworks Using Annotation Processing:
In Kotlin you specify the dependencies in a similar to Java way using Kotlin Annotation processing tool (kapt) instead of annotationProcessor.
Then I modified the build.gradle(Module:app) by changing all annotationProcessor to kapt, it works:
--- a/app/build.gradle
+++ b/app/build.gradle
## -2,6 +2,8 ## apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-android-extensions'
android {
// Butter Knife
implementation "com.jakewharton:butterknife:$butterknife_version"
- annotationProcessor "com.jakewharton:butterknife-compiler:$butterknife_version"
+ kapt "com.jakewharton:butterknife-compiler:$butterknife_version"
// Room
implementation "android.arch.persistence.room:runtime:$arch_lifecycle_version"
- annotationProcessor "android.arch.persistence.room:compiler:$arch_lifecycle_version"
+ kapt "android.arch.persistence.room:compiler:$arch_lifecycle_version"
// LifeCycle
implementation "android.arch.lifecycle:runtime:$arch_lifecycle_version"
implementation "android.arch.lifecycle:extensions:$arch_lifecycle_version"
implementation "android.arch.lifecycle:common-java8:$arch_lifecycle_version"
- annotationProcessor "android.arch.lifecycle:compiler:$arch_lifecycle_version"
+ kapt "android.arch.lifecycle:compiler:$arch_lifecycle_version"
// Dagger
implementation "com.google.dagger:dagger:$dagger_version"
implementation "com.google.dagger:dagger-android-support:$dagger_version"
- annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"
- annotationProcessor "com.google.dagger:dagger-android-processor:$dagger_version"
+ kapt "com.google.dagger:dagger-compiler:$dagger_version"
+ kapt "com.google.dagger:dagger-android-processor:$dagger_version"
}
If you use Butter Knife, you should also change to kapt, otherwise the views which are injected might be null.
in the Dao interface check that the annotations like #Query .. are imported from the room database class and not from somewhere else

Categories

Resources