Open domhys opened 2 years ago
This is very strange, its as if Hilt produced a bad metadata class and thus fails to read it at the root, if we can find the which metadata class was wrongly produced we might be able to better understand the issue.
Ideally creating a sample repro would be amazing, but I can see that being hard, and since sharing your project is not possible my other suggestion to you would be to attach a debugger to Hilt to try and figure out the issue. This comment has some instructions but I'll try to add to them.
kapt
one): compileOnly 'com.google.dagger:hilt-compiler:2.43.1'
The sources you should up in the IDE in the 'External Libraries' section.@Module
or @EntryPoint
that might be the cause. It might be possible the compiler stops there a lot, if that's the case it might be worth changing the breakpoint to not stop but just log the TypeElement element
parameter, so that the last item logged before the crash will point you somewhere. You have to get a bit detective here and gather as much info as possible../gradlew clean app:hiltJavaCompileDebug --no-daemon -Dorg.gradle.debug=true
, note that you might need to update the task, I used app:hiltJavaCompileDebug
there but yours might be different. Usually using the failing task would be good enough.That's it for now! Hopefully this will help you discover which metadata file is causing the crash. Note that once you find the type element you can further inspect the source and the originating @Module
or @EntryPoint
by looking at the generate metadata classes in their folders in build/generated/source/kapt
or build/generated/hilt
. Please do report back with as much info as you can gather to help us debug this.
@danysantiago I was able to attach a debugger over the weekend. The findings are very strange to me:
build.gradle
file using implementation(module)
)That's where I'm now. I don't want to move every class that's failing - it'd take too long. Even more bizarre are two things:
I tried debugging to find the difference between when the activity returns null and when it gives a correct result. It seems that it comes down to com.sun.tools.javac.model.JavacElements#nameToSymbol
When it's not working, Object sym = "symbol not found error" and nameStr = "packageName.Activity_GeneratedInjector"
, and when it does Object sym = "dagger.hilt.android.components.ActivityComponent" and nameStr = "dagger.hilt.android.components.ActivityComponent"
.
Please let me know if you have any ideas what can be causing this issue. If you have any additional questions or need me to debug/change something more, I'm happy to help.
I have a few more questions:
What version of Kotlin are you using?
What version of the Android Gradle Plugin are you using?
Are you developing in a Windows, Mac or Linux host?
Which JDK are you using (version and distribution)?
What happens if you turn off aggregation via the task:
hilt {
enableAggregatingTask = false
}
Do you have flavors and variants in your project?
The issue is definitely due to some cross-module classpath issue, i.e. while compiling :app
for some reason some classes in another module, say :library
are not being found, even if :app
depends on :library
. This might happen too if its a 2nd level dependency, say :app
-> :data
-> :network
, so it makes sense that moving the @Module
from a dependency Gradle module to the Application Gradle module might fix the issue. Note that moving packages / folders within the same Gradle module will likely have no effect, which it seems to be what you were trying a bit, and this makes sense since everything under a Gradle module regardless of folder structure is compiled together, where as different Gradle modules are compiled separately.
As to 5: Turning this option off seems to fix the issue. I was able to receive meaningful errors again and fix them. The whole project compiles now. But I don't understand why it worked. What's more, it works only with all hilt modules in the main app module - when I tried to move hilt modules back to separate android modules, it started giving nulls again. So it seems like turning off this option only fixes activities and fragments.
I submitted a change to improve the error message from that NPE to give us more information. Can you try running with Dagger from the head snapshots and try again? https://dagger.dev/dev-guide/versions has info on using the head snapshots.
@Chang-Eric I tried to do it, but somehow it downloads dagger 2.28.3. Should it work with hilt the same way as in the docs you provided? Gradle Dependencies show
| +--- com.google.dagger:dagger:HEAD-SNAPSHOT -> 2.28.3 (*)
| +--- com.google.dagger:dagger-lint-aar:HEAD-SNAPSHOT -> 2.28.3
| +--- com.google.dagger:hilt-core:HEAD-SNAPSHOT
| | +--- com.google.dagger:dagger:HEAD-SNAPSHOT -> 2.28.3 (*)
| | +--- com.google.code.findbugs:jsr305:3.0.2
| | \--- javax.inject:javax.inject:1
But previously I was able to determine with dependencies were problematic with the help of debugger, so this commit is an improvement for the future, not a solution to my problem at hand - I still don't know why
enableAggregatingTask = false
and more importantly@danysantiago Any ideas what can be the issue here or how to debug it further? I can try again to rebuild my project from scratch adding classes as I go and waiting for it to finally give me the same error, but it will take a lot of time.
I tried to do it, but somehow it downloads dagger 2.28.3.
@domhys, did you follow the last part of https://dagger.dev/dev-guide/versions:
Finally, due to Gradle’s versioning rules, you’ll also want to add a resolution strategy to ensure the HEAD-SNAPSHOT is not accidentally replaced by a numbered version of Dagger in your transitive dependencies. This setup usually goes in your application-level build.gradle file. For example:
// app-level build.gradle file configurations.all { resolutionStrategy.eachDependency { DependencyResolveDetails details -> if (details.requested.group == 'com.google.dagger') { details.useVersion "HEAD-SNAPSHOT" } } }
I did, but I must've pasted it in the wrong build.gradle file. It's working correctly now - it prints which module has problems.
error: [Hilt]
Could not get element for <package>.AnalyticsModule: java.lang.NullPointerException: Could not get element for <package>.AnalyticsModule
But as I said before - it doesn't solve my original problem. I still cannot migrate to Hilt because of these errors that I described in earlier comments. So I have to ask again:
@bcorso @danysantiago Any ideas what can be the issue here or how to debug it further? I can try again to rebuild my project from scratch adding classes as I go and waiting for it to finally give me the same error, but it will take a lot of time.
If <package>.AnalyticsModule
is null
it indicates that the class was not found in your class path.
One solution you could try is to add that dependency directly to your application. So, first find out which gradle library <package>.AnalyticsModule
belongs to, and then add that library as a dependency in your gradle application's build.gradle
dependencies.
@bcorso that's the problem - <package>.AnalyticsModule
is my own class. When this class is located in a separate android module, it throws that error. But once I move it to the main app module, it works correctly. So I have a way to make this work, but I want to have my hilt modules inside android modules that they refer to (exactly as I had with dagger). And I don't understand why hilt works like that - there must be some kind of other explanation as to why it's happening.
I want to have my hilt modules inside android modules that they refer to (exactly as I had with dagger)
Sorry, I'm not asking you to take the hilt modules out of the android modules they're currently in. I'm asking if you can try adding the android module as a direct dependency to your main app module by including it in the "dependencies" section of the build.gradle
.
@bcorso It already is included. AnalyticsModule
is a part of analytics
android module. And in my main app build.gradle file there's
dependencies {
implementation project(":analytics")
(...)
}
The modules configuration didn't change at all between dagger and hilt implementations.
Sorry, I don't really have any other ideas without being able to look into it myself. If you could provide a sample project with repro steps that would help a lot (I realize this is difficult, but not really seeing any other option here).
@bcorso @danysantiago I was able to create a small example that reproduces this issue: https://github.com/domhys/hiltTest My findings are quite strange and I'm hoping you can help me debug it further.
I started building this app from scratch adding new things waiting for the error message. I noticed that one external library was causing this error:
implementation("com.authenteq.android:flow:1.75.0")
When I commented out that line (even in the main project), Hilt was able to find AnalyticsModule again. However with that library included the error persists (please check the master branch in my repo).
However, that's not all. I experimented with changing package name of the app and found out that when I change the first part, the error also goes away even with the external library included. I've created a package
branch in the repo which differs from the master
branch only in package name (abc.example.android.app
vs be.example.android.app
). It seems that only changing the first part from be
to something else causes the error to go away (I also tried my.example.android.app
and there was no error as well).
Thanks for the repro project @domhys!
The TL:DR is that your project is running into some sort of JDK or Android Gradle Plugin (AGP) bug and this is not an issue specific to Hilt.
Indeed the library com.authenteq.android:flow:1.75.0
is a bit strange and is causing some sort of conflict when the compiler is trying to find classes in the classpath. Specifically it seems that the library is already obfuscated and it contains root package classes whose name are part of your classes' package which end up confusing the compiler and ultimately causes classes to not be found. I was able to confirm this with a simple processor and by completely removing Hilt.
The following processor simply tries to find your AnalyticsModule
:
@AutoService(Processor.class)
public class TheProcessor extends AbstractProcessor {
@Override
public Set<String> getSupportedAnnotationTypes() {
return Set.of("*");
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
TypeElement element = processingEnv.getElementUtils().getTypeElement("be.example.android.app.analytics.di.AnalyticsModule");
processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, "Got element: " + element);
assert element != null;
return false;
}
}
When configured to run with kapt: kapt(project(":TestProcessor"))
you'll notice it is unable to find the AnalyticsModule
's type element:
> Task :app:kaptDebugKotlin
warning: Got element: null
When debugging, deep in the JDK sources I see it insteads find a be.class
located in .gradle/caches/transforms-3/c287189ebb1c92f5e79e63008b6100f1/transformed/jetified-flow-1.75.0-runtime.jar
which is the jetified version of com.authenteq.android:flow:1.75.0
. When inspecting the jar it contains a class whose name is exactly the first part of your package:
unzip -l ~/Desktop/jetified-flow-1.75.0-runtime.jar | grep be
2773 12-31-1969 19:00 com/authenteq/android/flow/dagger/DaggerFlowComponent$be.class
6054 12-31-1969 19:00 be.class
The API that Hilt uses getTypeElement()
fails to find be.example.android.app.analytics.di.AnalyticsModule
because when looking for the package be
it instead finds a class be.class
and it stops searching.
That's as far as I was able to analyze the issue, which means this is an issue with that library, maybe because it is already obfuscated or maybe it's an issue with the jetifier, but it seems the library has not migrated to androidx which means you need the jetifier enabled so I was not able to confirm a workaround, it could also be a JDK bug so maybe trying using a newer JDK other than 11, but you might run into some other trouble...
As for the package names, as you have already discovered if you change your package to not be prefixed with one of the many possible root classes the jar contains then you'll avoid the issue since the compiler won't get confused when finding the type elements.
I don't think there much Hilt can do here (sorry!), I would try to update the project to remove Hilt and just have a simple processor (like the one above) that demonstrates the issue and share it with the AGP team.
I'm doing a migration from Dagger (with dagger-android) to Hilt. After completing all the steps from the migration guide, I'm getting a Null dependency error during compilation (full stacktrace at the end). At this point I'm not able to obtain any meaningful error message so I've got no idea what to fix.
What I've tried to do:
My setup: As this is a proprietary software, I'm not able to share the full source code, but my setup is pretty standard:
I'm aware that this is a hard bug to track down without any source code, but I'm posting for two reasons: