I have an issue with Dagger and my own generated code.
Assumptions:
I need to generate my own dagger component for UI tests purpose
I have my own Gradle's module for annotation processing which provides dagger component with dependencies. Call this GeneratedTestCoreComponent. This class is generated correctly
GeneratedTestCoreComponent is built at \build\generated\source\kapt\debug\...
GeneratedTestCoreComponent is used in dagger component, smth like this
#Component(modules = [UiTestModule::class],
dependencies = [GeneratedTestCoreComponent::class])
interface TestUiComponent {}
My annotation processor module is correctly added to gradle
implementation project(path: ':processor')
kapt(name: 'processor')
The issue is. During compilation I get below error
TestUiComponent.java:6: error: cannot find symbol
#com.dagger.Component(modules = {com.xxx.xxx.UiTestModule.class}, dependencies = {GeneratedTestCoreComponent.class})
symbol: class GeneratedTestCoreComponent
TestUiComponent.java:8: error: [ComponentProcessor:MiscError] com.dagger.internal.codegen.ComponentProcessor was unable to process this interface because not all of its dependencies could be resolved. Check for compilation errors or a circular dependency with generated code.
public abstract interface TestUiComponent
Additional info.
When I copy GeneratedTestCoreComponent class from build directory to src (keeping the same package) and disable my processor, then everything works fine
Try changing kapt(name: 'processor') into kapt project(':processor')
Related
In pursuit of "write once, run anywhere" integration tests, I am trying to move my test helpers into a Gradle module that can be included via testImplementation or androidTestImplementation. This helper module contains Espresso actions and assertions, which depend on View IDs and String resource identifiers from my app.
The problem -- When my helper module is included via androidTestImplementation, the module's resource references are only resolvable with the test context InstrumentationRegistry.context, rather than my app's InstrumentationRegistry.targetContext.
Is this expected? How else could I share resource reference-containing code between test and androidTest contexts, such that references always resolve to the target app context?
Sample code:
// :sharedtest Gradle module script
// Imports features in order to pull in their resource IDs
implementation(project(":features1"))
implementation(project(":features2"))
...
// Kotlin helpers inside :sharedtest Gradle module
import com.myapp.sharedtest.R
fun clickInsights() {
onView(withId(R.id.insights_tool)).perform(click())
}
...
// Integration test inside :app which
// includes :sharedtest module via androidTestImplementation
#Test
fun verifyClickInsights() {
// fails because com.myapp.sharedtest.R.id.insights_tool is not resolved as expected
clickInsights()
}
...
I explored Test Fixtures to house my test helpers, but seems AGP doesn't support them for Android Kotlin code at this time. I also considered source sets, but those have been deprecated in favor of Gradle modules.
I found success in changing my sharedtest helper imports to be child-module relative, i.e. com.myapp.feature1.R works, but com.myapp.sharedtest.R doesn't. But I'd like to
A) understand why this works and
B) avoid it if possible, since using sharedtest references everywhere is simplest codewise.
I have a homemade library that generates DataMapper classes.
They are generated with #Singleton and #Inject annotations to be able to inject them where i need them.
But where it doesn't work is when Dagger tries to create the dependency tree, this error shows :
:data:kaptGenerateStubsDebugKotlin
e: /Users/me/myproject/data/build/tmp/kapt3/stubs/debug/com/myproject/data/di/DataComponent.java:11: error: [Dagger/MissingBinding] error.NonExistentClass cannot be provided without an #Inject constructor or an #Provides-annotated method.
public abstract com.myproject.domain.repository.ContentRepository contentRepository();
^
error.NonExistentClass is injected at
com.myproject.data.repository.ContentDataRepository.<init>(…, myGeneratedDataMapper, …)
com.myproject.data.repository.ContentDataRepository is injected at
com.myproject.data.di.module.DataModule.contentRepository(contentDataRepository)
com.myproject.domain.repository.ContentRepository is provided at
com.myproject.data.di.DataComponent.contentRepository()
:data:kaptDebugKotlin
:data:kaptDebugKotlin FAILED
Involved classes are :
DataModule (module for dagger)
#Module
class DataModule {
#Provides
#Singleton
fun contentRepository(contentDataRepository: ContentDataRepository): ContentRepository = contentDataRepository
}
DataComponent (component for dagger):
#Singleton
#Component(modules = [DataModule::class])
interface DataComponent {
fun contentRepository(): ContentRepository
}
ContentDataRepository
#Singleton
class ContentDataRepository #Inject constructor(
private val myGeneratedDataMapper: MyGeneratedDataMapper
) : ContentRepository {
...
}
MyGeneratedDataMapper
#Singleton
class MyGeneratedDataMapper #Inject constructor() {
...
}
The thing is, if i disable kapt of dagger dependency in gradle.build, then build, then enable it, then build, it works.
If i do a clean + build, it doesn't work, same error.
I want to make it work in one row.
I don't know if you are using AS3.2 or AS3.3 with androidX artifacts or not but Maybe this is the case with you too.
so when i migrated to androidX artifacts in AS3.2 i got hit with bunch of NonExistentClass errors ends the build with
kaptGenerateStubsDebugKotlin
:data:kaptDebugKotlin
:data:kaptDebugKotlin
I finally found out that it has something to do with Dagger itself and degraded the version from 2.17 to 2.16 now the latest version of Dagger2 is 2.18 which i can't use due to this bug / feature [they forgot about].
Update:
i found the solution and it just came today so here is the issue tracker link:
https://issuetracker.google.com/issues/115738511
so the bug was not in the Dagger but it was with Jetifier and i totally ignored the fact that it was set enabled during migration
here's the solution i copied from the link:
Sorry jetifier beta01 was not binary compatible with alpha10.
We have published beta02 that should fix this issue.
Please try:
buildscript { dependencies {
classpath 'com.android.tools.build.jetifier:jetifier-processor:1.0.0-beta02' } }
You're probably not going to like my answer but the order is kinda random.
Look at this thread for some more explaining and maybe some more guidance but, if you want to verify you are running first look at Gradle plugins and how to use them
Simple scope annotation:
#Scope
#Retention(RUNTIME)
public #interface SimpleScope {
}
Simple component:
#SimpleScope
#Component
public interface SimpleComponent {
}
compiler error:
error: Scoping annotations are only allowed on concrete types and
#Provides methods
The compiler error is actually coming from Dagger 1 annotation processor. Specifically here: Dagger 1 ValidationProcessor. If the annotation processor sees that any interface is annotated with a javax.inject.Scope annotation, it reports an error. Even if the interface or scope are not used by Dagger 1 in any way.
We are currently migrating from Dagger 1 to Dagger 2, and hence both annotation processors are running on Gradle modules that use both Dagger 1 and Dagger 2.
One solution is to fully migrate each Gradle module, so that both annotation processors don't have to run on the same code. However, this is not always easy.
Our solution was to fork Dagger 1 and modify the ValidationProcessor to not fail if the interface is a Dagger 2 component.
I have used Data binding in my existing code and now I am migrating to Room for persistence.
I have followed the steps mentioned in Florina's Blog for room
My Code builds fine without java code error or BR related error when I remove room dependency
annotationProcessor 'android.arch.persistence.room:compiler:1.0.0'
and its runs too, but gives Runtime exception saying database_Impl does not exists. As it couldn't generate that's file.
But after I put Annotation processor back, it give me
Error:(29, 37) error: cannot find symbol class BR
My gradle plugin used is com.android.tools.build:gradle:3.0.1
They both don't seem to work together
Steps taken so far:
Changed BaseObservable to Observable As suggested here
Updated Android Studio to 3.0.1
Tried using gradle latest plugin canary 6
Clear, Clear Cache also done
Has anyone used Room and Data binding together ?
After 4 days of efforts I finally made my code run properly.
Steps to solve the
Data binding error like
error: package com.packagename.databinding does not exist
error: cannot find symbol class CustomMainActivityBinding
The app gradle must have below code added in order to view more than 100 errors that come by default
allprojects {
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.compilerArgs << "-Xmaxerrs" << "4000"
options.compilerArgs << "-Xmaxwarns" << "4000"
}
}
}
Gradle dependencies for data binding and Room arch components
annotationProcessor 'com.android.databinding:compiler:3.0.1'
implementation 'android.arch.lifecycle:extensions:1.0.0'
implementation 'android.arch.persistence.room:runtime:1.0.0'
annotationProcessor 'android.arch.lifecycle:compiler:1.0.0'
annotationProcessor 'android.arch.persistence.room:compiler:1.0.0'
Note: Gradle plugin version is 3.0.1
I changed my all VMs to implement Observable and call
registry.notifyChange(this, BR.bar);
in case of notify change and also implement overridden methods
#Override
public void addOnPropertyChangedCallback(OnPropertyChangedCallback
callback) {
registry.add(callback);
}
#Override
public void removeOnPropertyChangedCallback(
OnPropertyChangedCallback callback) {
registry.remove(callback);
}
These things made my code Build, but it run without exceptions when I solved the Room query related errors. Which was the main reason, code was building but not running. These errors I could see when I Rebuid my project again.
UPDATE:
After Android studio 3.1.3, Message window is gone and now all build error appears under Build view. Although there is toggle available to get textview response of error, for data-binding errors it isn't sufficient.
Solution that helped me:
In Command promt/Terminal navigate to project root.
Run this command "./gradlew build --stacktrace" if Mac or ".\gradlew
build --stacktrace" if Windows.
Now search for "error:" tag and the compile time errors will show up.
I couldn't get these errors in IDE.
In my experience, the following reasons may cause the error:
Incorrect getter/setter (missing or incorrect name)
Incorrect return type in Dao
annotationProcessor or kapt issues
The default constructor is overridden (you need to keep the empty constructor for Room)
I faced this issue while adding room dependencies. Add this in the below way to resolve the error.
def roomVersion = "2.0.0-rc01"
implementation "android.arch.persistence.room:runtime:$roomVersion"
annotationProcessor "android.arch.persistence.room:runtime:$roomVersion"
annotationProcessor "android.arch.persistence.room:compiler:$roomVersion"
I get following error message from Dagger when compiling the module:
test.MyClass is exclusively members injected and therefore cannot be scoped required by test.MyModule for test.MyModule
Google is no help in this case.
I have a quite simple architecture: 1 module, all injected classes are listed in injects clause. I don't see anything what may cause a problem.
There error seems to be caused by not having an #Inject constructor.
In my case, I was using lombok constructor generation on the class. IE.
#RequiredArgsConstructor(onConstructor = #__({#Inject}))
public class MyClass {
private final AnotherClass anotherClass;
}
And changing to an explicit constructor resolved the problem.
I expect the failure is related to dagger running before the generated code is generated. (Similar to this question and the related issue.)