Unresolved type error for a class in transitive dependency
See original GitHub issueDagger 2.41
Repro project: https://github.com/lwasyl/dagger-transitive-dependencies/tree/2634c3b3fb316fc877fc0e0919e79e36946efc31
If you run ./gradlew presentation:assemble
, the build will fail with a message that it can’t resolve ApiModel
. If you change Dagger version to 2.40.5 in settings.gradle
, the same command will succeed.
I see in the changelog more strict validation for unresolved annotations, but nothing for types. In this repro, there are no scopes or qualifiers, so I don’t know if the change is expected or not
Issue Analytics
- State:
- Created 2 years ago
- Reactions:3
- Comments:14
Top Results From Across the Web
Maven - Transitive dependencies are not resolved for artifact ...
To successfully resolve transitive dependencies, project B's jar and pom.xml must be accessible in the Maven repository.
Read more >IDE: "Cannot access class" false positive error with transitive ...
In a certain case, the Kotlin plugin seems to highlight errors of "Cannot access class" in the editor where they do not actually...
Read more >AS BumbleBee "Unresolved Reference" in test code
Open the JVM unit test in AS, observe that IDE shows an "Unresolved reference" error. This works fine in Chipmunk with AGP 7.2.1....
Read more >RE: Liferay 7, cannot resolve runtime dependency - Forums
Without doing any bnd.bnd modifications, when you deploy this module to OSGi you'll get the unresolved reference error because there is no other...
Read more >Unrelated packages Unresolved requirement Import-Package ...
This is due to third-party jar transitive dependencies. If we use compileInclude scope for third-party dependencies for gradle build type module ...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
@lwasyl, @GianfrancoMS just wanted to give an update.
TL;DR
Unfortunately, I don’t think we’ll be able to make the proposed changes, as they are more problematic than I initially thought.
As it turns out, even if we relax Dagger’s validation javac ends up failing conditionally depending on how exactly we implement the generated code (see details below). This makes our generated code fragile to otherwise benign changes to what should be implementation details. It also means that toggling on/off different build flags that change the internal implementation, e.g. fastInit mode, can cause unexpected breakages. Thus, while this may have worked okay for you in the past, it’s fragile and there’s no guarantee that some future change to our generated code won’t accidentally break you.
I do list some workarounds on our side that could likely avoid these issues (see below), but given that it adds complexity to our code base, reduces the readability of our generated code, and likely requires a lot more time/effort we’re going to continue to validate the types for these case. Hopefully all of this makes sense and seems reasonable to you, but let me know if not.
Javac Issues
As an example of how javac can conditionally fail based on our generated code, I’ll use
CoreInterface
from the sample app you linked.Before looking at each scenario, it’s important to understand that Dagger generates a factory class for each binding that contains both a static
create()
method and a staticnewInstance()
method that our generated code uses to create either an instance of the factory (e.g.Foo_Factory
) or type (e.g.Foo
) respectively.Scenario 1
In some cases we satisfy the request for a binding using
Factory#newInstance()
, e.g.This scenario fails javac because the call to
CoreModule_internalCoreInterfaceFactory.newInstance()
returnsInternalCoreInterface<ApiModel>
which referencesApiModel
(which is not on the classpath). Note that this happens even though we don’t explicitly referenceApiModel
anywhere in the generated code. Javac will fail with an error like:Scenario 2
In other cases, we need to use a
Provider
to satisfy the request usingFactory.create()
, e.g.In this case javac does not fail. It turns out that we get a bit lucky because the
CoreModule_internalCoreInterfaceFactory.create()
returns the subclass typeCoreModule_internalCoreInterfaceFactory
rather than its supertype,Provider<InternalCoreInterface<ApiModel>>
, which would have caused javac to fail due to the reference toApiModel
.Workarounds
One workaround to this issue is that we could change
Foo_Factory#newInstance()
to always returnObject
rather thanFoo
to avoid javac from having to know about the type when compiling the generated component. Unfortunately, we would have to do this for every binding since we can’t know apriori which classes will not be on the classpath. This also means that all of the input parameters for#newInstance()
and#create()
would also have to beObject
, which would add a lot more casts to the generated code. We would also need some version skew logic to check whether the generated factory was from a new enough version of Dagger to include these changes.@lwasyl that’s a good point, and we already do the processing for the
@Binds
within the Gradle module that defines it, so I agree we should be able to skip the check for@Binds
when processing the component. I’ll include this in the change.