dependency-analysis-gradle-plugin icon indicating copy to clipboard operation
dependency-analysis-gradle-plugin copied to clipboard

Task findDeclarations is not cacheable due to input based on object references

Open piotrkurek91 opened this issue 6 months ago • 2 comments

Plugin version 2.19.0

Gradle version 8.7

JDK version Eclipse Temurin OpenJDK Runtime Environment 21.0.4+7-LTS

** Describe the bug ** Remote and local Gradle build cache misses occur for the findDeclarations task from the @autonomousapps/dependency-analysis-gradle-plugin, even when inputs, outputs, and code are unchanged. This prevents cache hits between CI and local, and between builds on different machines. The issue is traced to the use of object references (e.g., ModuleInfo@5f9863a7) in the task’s @Input properties, resulting in non-deterministic cache keys.

** To Reproduce **

Apply the com.autonomousapps.dependency-analysis plugin with a custom dependencyAnalysis configuration. Run a build for a subproject (e.g., ./gradlew findDeclarations). Remove the build directory and run the build again. Observe that the task uses the local cache only if the Gradle daemon remains alive and creates objects in the same order. Remove the local build cache directory (~/.gradle/caches/build-cache-1/) and rerun the build. Observe that the task both misses local and remote cache, and only stores the result locally. Inspect the cache key inputs using a build scan or by printing declarationContainer.mapping; you will see object references with memory addresses that differ between builds. Expected behavior For identical project state and code, the findDeclarations task should produce the same cache key every time, resulting in consistent remote and local cache hits across machines and build environments.

Additional context

The input property declarationContainer.mapping contains object references (e.g., ModuleInfo@5f9863a7), whose hash codes or memory addresses differ between JVM executions. This results in different cache keys for each build, making cache hits impossible across JVMs, machines, or CI systems. Fixing this requires ensuring that all @Input/@Nested properties for the task use stable, serializable, value-based data (e.g., strings, numbers, lists/sets/maps with deterministic ordering and values), not object references. Build scan comparison between builds with no code changes shows different values for declarationContainer.mapping input.

piotrkurek91 avatar Jul 08 '25 16:07 piotrkurek91

Example of printing the value of this input:

Run #1
declarationContainer.mapping: [annotationProcessor:[(com.autonomousapps.internal.utils.ModuleInfo@45cd1907, GradleVariantIdentification(capabilities=[], attributes={org.gradle.category=platform}))], api:[(com.autonomousapps.internal.utils.ModuleInfo@bec5725, GradleVariantIdentification(capabilities=[], attributes={})), (com.autonomousapps.internal.utils.ModuleInfo@5289481a, GradleVariantIdentification(capabilities=[], attributes={})), (com.autonomousapps.internal.utils.ModuleInfo@561989c4, GradleVariantIdentification(capabilities=[], attributes={}))], compileOnly:[], compileOnlyApi:[], implementation:[(com.autonomousapps.internal.utils.ModuleInfo@7b31b721, GradleVariantIdentification(capabilities=[], attributes={org.gradle.category=platform}))], runtimeOnly:[(com.autonomousapps.internal.utils.ModuleInfo@6360f9c5, GradleVariantIdentification(capabilities=[], attributes={org.gradle.category=platform}))], testAnnotationProcessor:[], testCompileOnly:[(com.autonomousapps.internal.utils.ModuleInfo@a5cdff3, GradleVariantIdentification(capabilities=[], attributes={org.gradle.category=platform}))], testImplementation:[(com.autonomousapps.internal.utils.ModuleInfo@101120d5, GradleVariantIdentification(capabilities=[], attributes={org.gradle.category=platform})), (com.autonomousapps.internal.utils.ModuleInfo@6e6a8270, GradleVariantIdentification(capabilities=[], attributes={})), (com.autonomousapps.internal.utils.ModuleInfo@2256680, GradleVariantIdentification(capabilities=[], attributes={})), (com.autonomousapps.internal.utils.ModuleInfo@66ef1549, GradleVariantIdentification(capabilities=[], attributes={org.gradle.category=platform})), (com.autonomousapps.internal.utils.ModuleInfo@77e400e0, GradleVariantIdentification(capabilities=[], attributes={}))], testRuntimeOnly:[(com.autonomousapps.internal.utils.ModuleInfo@40876cd9, GradleVariantIdentification(capabilities=[], attributes={})), (com.autonomousapps.internal.utils.ModuleInfo@69bf1608, GradleVariantIdentification(capabilities=[], attributes={org.gradle.category=platform})), (com.autonomousapps.internal.utils.ModuleInfo@7a441fbb, GradleVariantIdentification(capabilities=[], attributes={}))]]

Run #2
declarationContainer.mapping: [annotationProcessor:[(com.autonomousapps.internal.utils.ModuleInfo@3bc45cc, GradleVariantIdentification(capabilities=[], attributes={org.gradle.category=platform}))], api:[(com.autonomousapps.internal.utils.ModuleInfo@34229116, GradleVariantIdentification(capabilities=[], attributes={})), (com.autonomousapps.internal.utils.ModuleInfo@1ee0b004, GradleVariantIdentification(capabilities=[], attributes={})), (com.autonomousapps.internal.utils.ModuleInfo@2a3e89d7, GradleVariantIdentification(capabilities=[], attributes={}))], compileOnly:[], compileOnlyApi:[], implementation:[(com.autonomousapps.internal.utils.ModuleInfo@4bcd2b79, GradleVariantIdentification(capabilities=[], attributes={org.gradle.category=platform}))], runtimeOnly:[(com.autonomousapps.internal.utils.ModuleInfo@50b6c294, GradleVariantIdentification(capabilities=[], attributes={org.gradle.category=platform}))], testAnnotationProcessor:[], testCompileOnly:[(com.autonomousapps.internal.utils.ModuleInfo@70bc53b5, GradleVariantIdentification(capabilities=[], attributes={org.gradle.category=platform}))], testImplementation:[(com.autonomousapps.internal.utils.ModuleInfo@2e921c44, GradleVariantIdentification(capabilities=[], attributes={org.gradle.category=platform})), (com.autonomousapps.internal.utils.ModuleInfo@461f390e, GradleVariantIdentification(capabilities=[], attributes={})), (com.autonomousapps.internal.utils.ModuleInfo@6a62bd6e, GradleVariantIdentification(capabilities=[], attributes={})), (com.autonomousapps.internal.utils.ModuleInfo@ca66c0c, GradleVariantIdentification(capabilities=[], attributes={org.gradle.category=platform})), (com.autonomousapps.internal.utils.ModuleInfo@78d17a6c, GradleVariantIdentification(capabilities=[], attributes={}))], testRuntimeOnly:[(com.autonomousapps.internal.utils.ModuleInfo@7966ebcd, GradleVariantIdentification(capabilities=[], attributes={org.gradle.category=platform})), (com.autonomousapps.internal.utils.ModuleInfo@75e1a8f6, GradleVariantIdentification(capabilities=[], attributes={})), (com.autonomousapps.internal.utils.ModuleInfo@610a042, GradleVariantIdentification(capabilities=[], attributes={}))]]

piotrkurek91 avatar Jul 08 '25 16:07 piotrkurek91

Thank you for the issue! Looking at the code, I think this could be as simple as making DeclarationContainer a data class. Alternatively, add custom hashCode and equals functions. Would you be interested in submitting such a PR?

autonomousapps avatar Jul 09 '25 22:07 autonomousapps