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

Error NoSuchMethodError com.google.common.collect.ImmutableMap #1140

Closed
PMiarka opened this issue Oct 16, 2023 · 13 comments
Closed

Error NoSuchMethodError com.google.common.collect.ImmutableMap #1140

PMiarka opened this issue Oct 16, 2023 · 13 comments
Labels
bug Something isn't working

Comments

@PMiarka
Copy link

PMiarka commented Oct 16, 2023

Description
A clear and concise description of what the bug is.

Steps to Reproduce

  1. get paparazzi sample project
  2. add dependency to paparazzi/sample/build.gradle
    testImplementation("com.lemonappdev:konsist:0.13.0")
  3. Run task of sample module -> recordPaparazziTests

error:

app.cash.paparazzi.sample.ComposeA11yTest > compositeItems FAILED
    java.lang.NoSuchMethodError: 'com.google.common.collect.ImmutableMap com.google.common.collect.ImmutableMap$Builder.buildOrThrow()'
        at com.google.common.collect.SparseImmutableTable.<init>(SparseImmutableTable.java:85)
        at com.google.common.collect.SparseImmutableTable.<clinit>(SparseImmutableTable.java:32)
        at com.google.common.collect.ImmutableTable.of(ImmutableTable.java:103)
        at com.google.common.collect.ImmutableTable$Builder.buildOrThrow(ImmutableTable.java:288)
        at com.google.common.collect.ImmutableTable$Builder.build(ImmutableTable.java:274)
        at app.cash.paparazzi.internal.resources.base.BasicStyleResourceItem.<init>(BasicStyleResourceItem.kt:64)
        at app.cash.paparazzi.internal.resources.RepositoryLoader.createStyleItem(RepositoryLoader.kt:737)
        at app.cash.paparazzi.internal.resources.RepositoryLoader.createResourceItem(RepositoryLoader.kt:525)
        at app.cash.paparazzi.internal.resources.RepositoryLoader.parseValueResourceFile(RepositoryLoader.kt:355)
        at app.cash.paparazzi.internal.resources.RepositoryLoader.loadResourceFile(RepositoryLoader.kt:308)
        at app.cash.paparazzi.internal.resources.RepositoryLoader.loadResourceFile(RepositoryLoader.kt:221)
        at app.cash.paparazzi.internal.resources.RepositoryLoader.loadFromResFolder(RepositoryLoader.kt:202)
        at app.cash.paparazzi.internal.resources.RepositoryLoader.loadRepositoryContents(RepositoryLoader.kt:163)
        at app.cash.paparazzi.internal.resources.FrameworkResourceRepository$Loader.loadRepositoryContents(FrameworkResourceRepository.kt:235)
        at app.cash.paparazzi.internal.resources.FrameworkResourceRepository.load(FrameworkResourceRepository.kt:97)
        at app.cash.paparazzi.internal.resources.FrameworkResourceRepository.access$load(FrameworkResourceRepository.kt:38)
        at app.cash.paparazzi.internal.resources.FrameworkResourceRepository$Companion.create(FrameworkResourceRepository.kt:359)
        at app.cash.paparazzi.internal.Renderer.prepare(Renderer.kt:73)
        at app.cash.paparazzi.Paparazzi.prepare(Paparazzi.kt:158)
        at app.cash.paparazzi.Paparazzi$apply$statement$1.evaluate(Paparazzi.kt:124)
        at app.cash.paparazzi.agent.AgentTestRule$apply$1.evaluate(AgentTestRule.kt:17)
        at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
        at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
        at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
        at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
        at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
        at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:112)
        at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
        at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:40)
        at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:60)
        at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:52)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
        at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
        at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
        at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
        at jdk.proxy1/jdk.proxy1.$Proxy2.processTestClass(Unknown Source)
        at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:176)
        at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
        at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
        at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
        at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
        at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:113)
        at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:65)
        at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
        at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)

Similar problem but probably caused by the same reason I face in my personal project, but there the error is:

java.lang.NoSuchMethodError at SparseImmutableTable.java:85

Expected behavior
recordParaprazziDebug works as normal

Additional information:

  • Paparazzi Version: 1.3.1
  • OS: MacOS: Ventura 13.6
  • Compile SDK: 33
  • Gradle Version: 8.3
  • Android Gradle Plugin Version: 8.1.1

Basing on research it is related to guava version.
I tried to exclude from konsist guava, but it do not work.

Are there any other options to fix it?

@PMiarka PMiarka added the bug Something isn't working label Oct 16, 2023
@TWiStErRob
Copy link
Contributor

Interesting, because according to https://mvnrepository.com/artifact/com.lemonappdev/konsist/0.13.0 there's no Guava dep there. Anyway, since the error is coming from guava related classes. I still recommend looking at the issue with the process I did here: #906

Also make sure that without that dependency (and no other changes) the tests actually work, to prevent unnecessary investigation related to Konsist.

Would you be able to provide a minimal repro? (e.g. one where uncommenting a line produces this behavior)

@PMiarka
Copy link
Author

PMiarka commented Oct 24, 2023

Thanks for your comment.
I did some investigation and still do not see how to fix it.
In case of paparazzi.sample project the fix you have found in linked issue #906 works. (adding api("com.google.guava:guava:32.1.3-jre"))

But in my case it is more complex project and we use some additional dependencies.
I tried to dig using dependencyInsight but haven't found solution yet.
I did not have time to find and prepare a sample where you can reproduce this issue. Once I do It for sure I will provide the repo here.

@PMiarka
Copy link
Author

PMiarka commented Jan 5, 2024

@TWiStErRob I did some more investigation and it seems that konsist + org.jetbrains.kotlinx:kotlinx-coroutines-test cause the error in my project.
In that case the fix with api("com.google.guava:guava:32.1.3-jre") do not work.

To reproduce error you can checkout the branch:

https://github.com/PMiarka/paparazzi/tree/bug/1140_konsist_incompatibiltiy

uncomment testImplementation libs.test.coroutines in build.gradle (:sample) and run test ComposeA11yTest
when it is commented out the test works, otherwise it cause error:

java.lang.NoSuchMethodError: 'com.google.common.collect.ImmutableMap com.google.common.collect.ImmutableMap$Builder.buildOrThrow()'

@TWiStErRob
Copy link
Contributor

TWiStErRob commented Jan 5, 2024

Had a quick look, and I can confirm that depInsight is the same w/o coroutines.
gradlew :sample:depIn --configuration debugUnitTestRuntimeClasspath --dependency com.google.guava:guava

I noticed that SparseImmutableTable is different on exactly this line between guava 31 and 32. However the called method is in the same jar.

I will have a look tomorrow, but my hunch is that there's a non-repackaged version somewhere. I'm planning to debug the class/jar file location w/o coroutines.

@TWiStErRob
Copy link
Contributor

TWiStErRob commented Jan 6, 2024

I executed this:

gradlew :sample:testDUT --tests ComposeA11yTest --rerun --debug-jvm

Then added a breakpoint at SparseImmutableTable:30 (static final EMPTY =), when it hit, I evaluated:

java.util.Arrays.asList(
	com.google.common.collect.SparseImmutableTable.class.getProtectionDomain().getCodeSource().getLocation(),
	com.google.common.collect.ImmutableMap.Builder.class.getProtectionDomain().getCodeSource().getLocation()
)

and got:

com.google.guava/guava/32.0.1-jre/guava-32.0.1-jre.jar
org.jetbrains.kotlin/kotlin-compiler/1.9.10/kotlin-compiler-1.9.10.jar

😮

image

I diffed gradlew :sample:dep w/o coroutines and it doesn't show anything related to kotlin-compiler, it was there all along (via konsist). I had a similar issue before with something: when your dependencies change, Gradle reshuffles them in a non-deterministic order. So that's one issue, but the root cause is that the dependencies contain duplicate classes. Konsist tracks this at https://lemonappdev.atlassian.net/jira/software/c/projects/KON/issues/KON-576 and I reported to see if Kotlin can do anything about this directly: https://youtrack.jetbrains.com/issue/KT-64774

As for workaround for your crash, I'm not sure what to do, you can try these long shots:

  • excluding kotlin-compiler, which I'm sure will break konsist
  • use some Gradle metadata magic to replace kotlin-compiler with kotlin-compiler embeddable yourself praying its API is the same.
  • force a guava version on your classpath that matches kotlin-compler's packaged version, so that the classes from the 2 jars are compatible.
  • not use konsist and paparazzi in the same module
  • add some other random dependencies until you get the ordering "just right"

@jrodbx
Copy link
Collaborator

jrodbx commented Jan 7, 2024

This is related to the Truth/Guava issue referenced here: #1206

Applying this workaround in sample/build.gradle fixed the issue for me given the provided repro steps.

@jrodbx jrodbx closed this as completed Jan 7, 2024
@TWiStErRob
Copy link
Contributor

@jrodbx for me the workaround did not fix the issue. Did you uncomment the coroutines line as described here: #1140 (comment)?


But, anyway, it's fair to close this as we cannot do anything here, konsist needs to be fixed. I would also recommend stop using konsist until it uses kotlin-compiler-embeddable as JetBrains resolved the issue with that recommendation. Or create a separate module for architectural or screenshot tests.

@PMiarka
Copy link
Author

PMiarka commented Jan 8, 2024

Thanks for you time. I really appreciate it!
Im impressed how deep you both dive into this issue.

I completely agree that it is fair to close this issue.

You guys do awesome work, thanks for paparazzi! :)

@TWiStErRob
Copy link
Contributor

@PMiarka Can you try if this works for you at runtime when running konsist?

configurations.all {
    // https://docs.gradle.org/current/userguide/resolution_rules.html#sec:dependency_substitution_rules
    resolutionStrategy.dependencySubstitution {
        substitute(module("org.jetbrains.kotlin:kotlin-compiler"))
            .using(module("org.jetbrains.kotlin:kotlin-compiler-embeddable:1.9.10"))
    }
}

@PMiarka
Copy link
Author

PMiarka commented Jan 8, 2024

I verified it and it works!
But as we are using 1.9.21 in project I replaced the version so i used:

configurations.all {
    // https://docs.gradle.org/current/userguide/resolution_rules.html#sec:dependency_substitution_rules
    resolutionStrategy.dependencySubstitution {
        substitute(module("org.jetbrains.kotlin:kotlin-compiler"))
            .using(module("org.jetbrains.kotlin:kotlin-compiler-embeddable:1.9.21"))
    }
}

Big kudos for you help!

@jrodbx
Copy link
Collaborator

jrodbx commented Jan 8, 2024

Did you uncomment the coroutines line as described here: #1140 (comment)?

No, I did not. I only followed the OP's repro steps (added testImplementation("com.lemonappdev:konsist:0.13.0") and ran ./gradlew rPD to repro, then added the workaround to succeed.

@igorwojda
Copy link

Hey All

Let me drop an update here as Konsist maintainer.

First of all this is quite impressive investigation 👏👏👏

I was able to replace kotlin-compiler with kotlin-compiler-embeddable (LemonAppDev/konsist#954). This change will be released next week as part of Konsist 0.15.0.
In the mean time you can give it a try it and let me know if this works as expected (no .using(module("org.jetbrains.kotlin:kotlin-compiler-embeddable workaround needed).

Artifact is public, however snapshots repo has to be added to the project. The version 0.15.0-SNAPSHOT contains the fix (see PR for more details).

BTW I was not aware of this issue for some time. It’s always good to repost such problems to Konsist slack channel, start new GitHub discussion at Konsist repo or just tag me to make things smoother in the future ;-)

@TWiStErRob
Copy link
Contributor

@igorwojda I've tested it with:

Index: sample/build.gradle
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/sample/build.gradle b/sample/build.gradle
--- a/sample/build.gradle	(revision 85696ae12ec4bae38b2cbec20c76a7324056422c)
+++ b/sample/build.gradle	(date 1710966933236)
@@ -24,11 +24,18 @@
   }
 }
 
+repositories {
+  maven { name = "Sonatype 01"; url = "https://s01.oss.sonatype.org/content/repositories/snapshots/" }
+}
+
 dependencies {
+  api libs.guava
   implementation libs.composeUi.material
   implementation libs.composeUi.uiTooling
 
   testImplementation libs.testParameterInjector
+  testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3")
+  testImplementation("com.lemonappdev:konsist:XXX")
 }
 
 // https://github.com/diffplug/spotless/issues/1572

XXX

  • 0.13.0 - as in OP
  • 0.14.0 - as in OP
  • 0.15.0-SNAPSHOT - green test

However the results are not fully conclusive, because 0.15.0 changes the dependency tree and therefore result in a different ordering. The relative order of konsist, guava, kotlin-compiler and other deps have changed, but I can confirm that com.guava is not present in any of the new .jars on the classpath.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants