Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

java.util.NoSuchElementException with Dagger 2.27 #1793

Open
tasomaniac opened this issue Apr 1, 2020 · 18 comments
Open

java.util.NoSuchElementException with Dagger 2.27 #1793

tasomaniac opened this issue Apr 1, 2020 · 18 comments

Comments

@tasomaniac
Copy link

Just tried upgrading our app to Dagger 2.27 and removed all JvmStatic annotations and get this internal error in compilation. Dagger expects something to be available but it is not. The error message does not really give any information.

Let me know how I can provide more information. Thanks

> Task app:kaptDebugAndroidTestKotlin FAILED
e: [kapt] An exception occurred: java.util.NoSuchElementException: No value present
        at java.util.Optional.get(Optional.java:135)
        at dagger.internal.codegen.bindinggraphvalidation.IncompatiblyScopedBindingsValidator.lambda$visitGraph$1(IncompatiblyScopedBindingsValidator.java:74)
        at java.util.Optional.ifPresent(Optional.java:159)
        at dagger.internal.codegen.bindinggraphvalidation.IncompatiblyScopedBindingsValidator.visitGraph(IncompatiblyScopedBindingsValidator.java:71)
@tasomaniac
Copy link
Author

It is also reproducible with 2.26

@danysantiago
Copy link
Member

The error is occurring on the incompatible scope validator, when a binding has a scope that the component does not have.

I wish Dagger had a processor option that logs elements being visited so that tracing when a failure happens is easier. Anyway, you can get us more information by attaching a debugger into the Dagger compiler. For kapt you can do this with a command like:

./gradlew clean app:kaptDebugKotlin --no-daemon -Dorg.gradle.debug=true -Dkotlin.compiler.execution.strategy="in-process" -Dkotlin.daemon.jvm.options="-Xdebug,-Xrunjdwp:transport=dt_socket\,address=5005\,server=y\,suspend=n"

Then in the IDE add a new run configuration of the 'Remote' category and when the command above start click the 'attach debug' icon. There are more instructions (with screenshots) in this comment.

A breakpoint inside the for-each in IncompatiblyScopedBindingsValidator#visitGraph() might help you find the binding element that is causing the issue.

@tasomaniac
Copy link
Author

Thanks for the detailed reply. I will try that.

Should this be caught earlier to signal a proper error message? Or is it not possible?

@danysantiago
Copy link
Member

danysantiago commented Apr 2, 2020

Sorry, I think I wasn't very clear, the error you are seeing is occurring during the incompatible scope validation, but does not mean that the actual error is an invalid scope. Instead a failing assertion expectation is occurring in the processor, an optional that is always suppose to be present is not, basically a NPE. If you can find more information we can figure out if it was something we can error out earlier of its really a processor issue, a missed case of some sort.

[Edit]: Specifically if you can find the location in your source code that is causing the issue and share the code with us then that would be very helpful.

@tasomaniac
Copy link
Author

Understood 👍 that makes sense. I'm doing this now. Which properties/fields should I be looking at to find "elements being visited"

@tasomaniac
Copy link
Author

Gradle naively thinks that the build is at 98% 😄 It's been 26min and I would say this is like 1/3 of our build. The error happens at the top level. Up to this point, it normally takes ~30sec. I guess debugging is supposed to be slower but is it expected to be that slow?

image

@tasomaniac
Copy link
Author

tasomaniac commented Apr 2, 2020

Ok, I got it. So this is happening on connected androidTest resources. We have TestAppComponent there which is a copy the AppComponent we use in the app.

It looks like this.

@Component(modules = [
    ...,
    FragmentBindingsModule::class,
    ...
])
@PerApplication
@NetworkScope
interface TestAppComponent : AndroidInjector<TestApp> {

    @Component.Factory
    interface Factory : AndroidInjector.Factory<TestApp> {
        override fun create(@BindsInstance instance: TestApp): TestAppComponent
    }
}

The app builds fine btw and has the following AppComponent

@Component(modules = [...])
@PerApplication
@NetworkScope
public interface AppComponent extends AndroidInjector<App> {

    @Component.Factory
    interface Factory extends AndroidInjector.Factory<App> {
    }
}

We put FragmentBindingsModule::class into the TestAppComponent extra because we use fragment-testing AndroidX library to instantiate and test Fragments in isolation. The scope @PerFragment is used in one of the classes injected in a Fragment and it is simply not available. In our normal app @PerFragment is added to respective Fragment's Subcomponent.

I guess there should really be a human readable error here. It should say something like "The @PerFragment scope was used in injected class Foo but not defined in the Component"

Edit: Actually @PerFragment annotation is already added in @ContributesAndroidInjector in FragmentBindingsModule. So it should just work. Here is a screenshot from the debugger.

image

@tasomaniac
Copy link
Author

Here is where the comparison fails:

image

com.wayfair.partners.whc.app.di.TestAppComponent → com.wayfair.partners.whc.app.di.FragmentBindingsModule_ScanFragment.ScanFragmentSubcomponent

vs.

com.wayfair.partners.whc.app.di.TestAppComponent → com.wayfair.partners.whc.app.di.ActivityBindingsModule_WarehouseCompanionActivityInjector.WarehouseCompanionActivitySubcomponent → com.wayfair.partners.whc.app.di.FragmentBindingsModule_ScanFragment.ScanFragmentSubcomponent

I guess while building androidTest, the main source set is also available and it gets mixed up.

  • In the first one in tests, Fragments are provided directly at TestAppComponent level
  • 2nd one, Fragments go through our single Activity.

@tasomaniac
Copy link
Author

Any chance that you can have a look into this? This is blocking for us to upgrade our Dagger version.

@vRallev
Copy link

vRallev commented Oct 7, 2020

We recently ran into this issue, too. The error message is not helpful at all. A module used in a subcomponent was added to a parent component accidentally and triggered this error. Unfortunately, I cannot share the source code.

[2020-10-07 22:05:59] FAILURE: Build failed with an exception.
[2020-10-07 22:05:59] 
[2020-10-07 22:05:59] * What went wrong:
[2020-10-07 22:05:59] Execution failed for task ':module:compileReleaseJavaWithJavac'.
[2020-10-07 22:05:59] > java.util.NoSuchElementException: No value present
[2020-10-07 22:05:59] Caused by: java.util.NoSuchElementException: No value present
[2020-10-07 22:05:59] 	at java.base/java.util.Optional.get(Optional.java:148)
[2020-10-07 22:05:59] 	at dagger.internal.codegen.binding.SubcomponentDeclaration$Factory.forModule(SubcomponentDeclaration.java:72)
[2020-10-07 22:05:59] 	at dagger.internal.codegen.binding.ModuleDescriptor$Factory.createUncached(ModuleDescriptor.java:178)
[2020-10-07 22:05:59] 	at dagger.internal.codegen.base.Util.reentrantComputeIfAbsent(Util.java:33)
[2020-10-07 22:05:59] 	at dagger.internal.codegen.binding.ModuleDescriptor$Factory.create(ModuleDescriptor.java:138)
[2020-10-07 22:05:59] 	at com.google.common.collect.Iterators$6.transform(Iterators.java:783)
[2020-10-07 22:05:59] 	at com.google.common.collect.TransformedIterator.next(TransformedIterator.java:47)
[2020-10-07 22:05:59] 	at com.google.common.graph.Traverser$GraphTraverser$DepthFirstIterator.computeNext(Traverser.java:456)
[2020-10-07 22:05:59] 	at com.google.common.collect.AbstractIterator.tryToComputeNext(AbstractIterator.java:141)
[2020-10-07 22:05:59] 	at com.google.common.collect.AbstractIterator.hasNext(AbstractIterator.java:136)
[2020-10-07 22:05:59] 	at com.google.common.collect.ImmutableCollection$Builder.addAll(ImmutableCollection.java:455)
[2020-10-07 22:05:59] 	at com.google.common.collect.ImmutableSet$Builder.addAll(ImmutableSet.java:512)
[2020-10-07 22:05:59] 	at com.google.common.collect.ImmutableSet.copyOf(ImmutableSet.java:246)
[2020-10-07 22:05:59] 	at com.google.common.collect.ImmutableSet.copyOf(ImmutableSet.java:228)
[2020-10-07 22:05:59] 	at dagger.internal.codegen.binding.ModuleDescriptor$Factory.transitiveModules(ModuleDescriptor.java:214)
[2020-10-07 22:05:59] 	at dagger.internal.codegen.binding.ComponentDescriptorFactory.create(ComponentDescriptorFactory.java:144)
[2020-10-07 22:05:59] 	at dagger.internal.codegen.binding.ComponentDescriptorFactory.subcomponentDescriptor(ComponentDescriptorFactory.java:88)
[2020-10-07 22:05:59] 	at dagger.internal.codegen.binding.ComponentDescriptorFactory.getDescriptorForComponentMethod(ComponentDescriptorFactory.java:232)
[2020-10-07 22:05:59] 	at dagger.internal.codegen.binding.ComponentDescriptorFactory.create(ComponentDescriptorFactory.java:165)
[2020-10-07 22:05:59] 	at dagger.internal.codegen.binding.ComponentDescriptorFactory.subcomponentDescriptor(ComponentDescriptorFactory.java:88)
[2020-10-07 22:05:59] 	at dagger.internal.codegen.ComponentProcessingStep.processSubcomponent(ComponentProcessingStep.java:126)
[2020-10-07 22:05:59] 	at dagger.internal.codegen.ComponentProcessingStep.process(ComponentProcessingStep.java:96)
[2020-10-07 22:05:59] 	at dagger.internal.codegen.ComponentProcessingStep.process(ComponentProcessingStep.java:53)
[2020-10-07 22:05:59] 	at dagger.internal.codegen.validation.TypeCheckingProcessingStep.lambda$process$0(TypeCheckingProcessingStep.java:51)
[2020-10-07 22:05:59] 	at com.google.common.collect.RegularImmutableMap.forEach(RegularImmutableMap.java:185)
[2020-10-07 22:05:59] 	at dagger.internal.codegen.validation.TypeCheckingProcessingStep.process(TypeCheckingProcessingStep.java:48)
[2020-10-07 22:05:59] 	at dagger.internal.codegen.validation.TypeCheckingProcessingStep.process(TypeCheckingProcessingStep.java:34)
[2020-10-07 22:05:59] 	at dagger.internal.codegen.statistics.DaggerStatisticsCollectingProcessingStep.process(DaggerStatisticsCollectingProcessingStep.java:52)
[2020-10-07 22:05:59] 	at dagger.shaded.auto.common.BasicAnnotationProcessor$ProcessingStepAsStep.process(BasicAnnotationProcessor.java:495)
[2020-10-07 22:05:59] 	at dagger.shaded.auto.common.BasicAnnotationProcessor.process(BasicAnnotationProcessor.java:228)
[2020-10-07 22:05:59] 	at dagger.shaded.auto.common.BasicAnnotationProcessor.process(BasicAnnotationProcessor.java:208)
[2020-10-07 22:05:59] 	at org.gradle.api.internal.tasks.compile.processing.DelegatingProcessor.process(DelegatingProcessor.java:62)
[2020-10-07 22:05:59] 	at org.gradle.api.internal.tasks.compile.processing.IsolatingProcessor.process(IsolatingProcessor.java:50)
[2020-10-07 22:05:59] 	at org.gradle.api.internal.tasks.compile.processing.DelegatingProcessor.process(DelegatingProcessor.java:62)
[2020-10-07 22:05:59] 	at org.gradle.api.internal.tasks.compile.processing.TimeTrackingProcessor.access$401(TimeTrackingProcessor.java:37)
[2020-10-07 22:05:59] 	at org.gradle.api.internal.tasks.compile.processing.TimeTrackingProcessor$5.create(TimeTrackingProcessor.java:99)
[2020-10-07 22:05:59] 	at org.gradle.api.internal.tasks.compile.processing.TimeTrackingProcessor$5.create(TimeTrackingProcessor.java:96)
[2020-10-07 22:05:59] 	at org.gradle.api.internal.tasks.compile.processing.TimeTrackingProcessor.track(TimeTrackingProcessor.java:117)
[2020-10-07 22:05:59] 	at org.gradle.api.internal.tasks.compile.processing.TimeTrackingProcessor.process(TimeTrackingProcessor.java:96)
[2020-10-07 22:05:59] 	at jdk.compiler/com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:980)
[2020-10-07 22:05:59] 	at jdk.compiler/com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:896)
[2020-10-07 22:05:59] 	at jdk.compiler/com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:1222)
[2020-10-07 22:05:59] 	at jdk.compiler/com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1334)
[2020-10-07 22:05:59] 	at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1258)
[2020-10-07 22:05:59] 	at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:936)
[2020-10-07 22:05:59] 	at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.lambda$doCall$0(JavacTaskImpl.java:104)
[2020-10-07 22:05:59] 	at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.handleExceptions(JavacTaskImpl.java:147)

Dagger should be able to handle this case, no?

@bcorso
Copy link

bcorso commented Oct 8, 2020

We recently ran into this issue, too. The error message is not helpful at all. A module used in a subcomponent was added to a parent component accidentally and triggered this error.

@vRallev, yeah the error message is not very helpful in understanding what circumstance led to the error, which unfortunately makes it very difficult for us to repro the error with just a stack trace. This type of error is never meant to be hit by users, and it typically means that an invariant that we've assumed in the code has somehow been broken.

Dagger should be able to handle this case, no?

It's very difficult to say until we've understood exactly what is causing the issue. In your case, the error message indicates that an element which we thought was a module doesn't have an @Module annotation, but it's not obvious how that's related to your repro description: "A module used in a subcomponent was added to a parent component." I tried to reproduce this locally, but I couldn't. If there's any way you could give a minimal repro example or add more concrete steps to reproduce the error, that would help.

@vRallev
Copy link

vRallev commented Oct 8, 2020

We have a very large codebase and I was made aware of this issue for the first time. I'm not aware it happened before and I can't reproduce it outside of our codebase either. I understand that you can't make random suggestions in the error messages either. May I suggest that you change this error message and ask for help what triggered it? Maybe then you'd get more hints in this ticket.

@tasomaniac
Copy link
Author

This is actually rather easy to reproduce.

@bcorso
Copy link

bcorso commented Oct 9, 2020

@tasomaniac I know you gave quite a bit of information above, but if you can you provide an example project reproducing the error that would be great?

@tasomaniac
Copy link
Author

I will try to reserve some time soon. Actually what @vRallev mentions is indeed very similar and can be even easier to provide a sample.

@0legg
Copy link

0legg commented Jan 12, 2022

I've faced the same kind of error as @vRallev (well, in the same codebase) when moving classes from one Gradle module to another. The only change in code structure was making some dependencies of a module implementation rather than api, so some parent components are not visible anymore. Anyway, one way or another, it's impossible to pinpoint what was the root cause, as even with --stacktrace there are 0 references to our code, only annotation processor, dagger and java internals.

@tasomaniac
Copy link
Author

At least working on this area to make error messages easier to understand with relevant references can make a huge difference even though it means the issue is hard to pinpoint and fix.

@bcorso
Copy link

bcorso commented Jan 13, 2022

@0legg @tasomaniac you'll be happy to know we are indeed currently working on fixing these types of issues so that you get a proper error message.

Part of the fix is improving the error messages for superficial validation (#2208), and the other part is making sure we have sufficient superficial validation for all types before we use them.

This particular issue is due to a lack of superficial validation before using a Module. Stacktraces like in #1793 (comment) are super helpful for us to pinpoint where we are missing this validation, but sometimes even with the stacktrace it's difficult to determine exactly how we got in that state. Thus, even better would be if you could provide a sample project that reproduces the issue, or debug in AndroidStudio/Intellij using the instructions in #3090 (comment) to give us more information about the setup that causes this failure. Once we know exactly how we got in this state, we can write a regression test and fix the issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants