detekt / detekt

Static code analysis for Kotlin
https://detekt.dev
Apache License 2.0
6.1k stars 758 forks source link

Using detekt Gradle plugin with Kotlin 1.3.71 causes NoClassDefFoundError #2501

Closed sschuberth closed 4 years ago

sschuberth commented 4 years ago

Expected Behavior

Upgrading from Kotlin 1.3.70 to Kotlin 1.3.71 should not have any effect on running detekt.

Observed Behavior

detekt starts to throw:

Caused by: java.lang.NoClassDefFoundError: kotlin/ExceptionsKt
    at kotlin.io.CloseableKt.closeFinally(Closeable.kt:58)
    at io.gitlab.arturbosch.detekt.cli.runners.Runner.execute(Runner.kt:30)

Steps to Reproduce

Check out the branch at https://github.com/oss-review-toolkit/ort/pull/2409 and run ./gradlew detekt.

Context

Your Environment

BraisGabin commented 4 years ago

Really strange... and the Linux/Windows errors are different: https://travis-ci.com/github/oss-review-toolkit/ort/builds/154679817#L1009

java.lang.NoClassDefFoundError: com/beust/jcommander/ParameterException
    at io.gitlab.arturbosch.detekt.invoke.DefaultCliInvoker.invokeCli(DetektInvoker.kt:46)
    at io.gitlab.arturbosch.detekt.Detekt.check(Detekt.kt:214)
schalkms commented 4 years ago

Mhmm, does it work with detekt version 1.6.0 ?

sschuberth commented 4 years ago

Yes, it does.

arturbosch commented 4 years ago

Judging from the fact that this was a CI build I guess it is a clean environment where the Gradle Daemon is not chached? If the Gradle Daemon was somehow cached, you need to restart it with 1.7.0.

sschuberth commented 4 years ago

Judging from the fact that this was a CI build I guess it is a clean environment where the Gradle Daemon is not chached?

Correct.

If the Gradle Daemon was somehow cached, you need to restart it with 1.7.0.

I'm getting the same error locally even when running ./gradlew --stop before.

sschuberth commented 4 years ago

This was fixed in detekt 1.7.1, probably thanks to PR https://github.com/arturbosch/detekt/pull/2507.

schalkms commented 4 years ago

@sschuberth thanks for testing this so quickly and closing it immediately! This saves time for us. 🙂

sschuberth commented 4 years ago

However, I do get other very weird errors with detekt 1.7.1 now :cry: I'll file a new issue.

sschuberth commented 4 years ago

I spoke too early, I still actually see the same issue with detekt 1.7.1, but also still with different errors on Linux / Windows, which confused me.

sschuberth commented 4 years ago

Current errors look like

sschuberth commented 4 years ago

Fixed in detekt 1.7.2, probably as a side effect of fixing #2527, see

sschuberth commented 4 years ago

FYI, I see the same happening again with detekt 1.7.4 after upgrading our app to Kotlin 1.3.72, but the root cause seems to be that in our app we're forcing the kotlin-reflect version like

// Ensure that all transitive versions of "kotlin-reflect" match our version of "kotlin-stdlib".
force("org.jetbrains.kotlin:kotlin-reflect:$kotlinPluginVersion")

Not sure why it makes a difference, but the detekt task works fine again after removing that line.

arturbosch commented 4 years ago

@sschuberth hm that's a good hint. Maybe we see this strange behavior lately because we removed our dependency on kotlin-reflect in 1.7.0 - https://github.com/arturbosch/detekt/pull/2405/files.

sschuberth commented 4 years ago

Hmm, I'm not sure. I'm more surprised why I also always see something about JCommander in the stacktrace. Why does the Gradle plugin depend on CLI parsing anyway?

arturbosch commented 4 years ago

The gradle plugin does not depend on it but the cli does which we call reflectively.

sschuberth commented 4 years ago

Wow, that sounds like an... interesting design choice 😄

arturbosch commented 4 years ago

Wow, that sounds like an... interesting design choice smile

Remember when the gradle plugin was 4x slower than the cli? That's why we now cache classloaders and call detekt reflectively :)

sschuberth commented 4 years ago

Remember when the gradle plugin was 4x slower than the cli?

TBH, I never noticed, as I a) never compared to using the CLI manually, and b) mostly leave running detekt to CI 😁

That's why we now cache classloaders and call detekt reflectively :)

But still interesting if the slowdown was caused by classloader lookups!

sschuberth commented 3 years ago

The gradle plugin does not depend on it but the cli does which we call reflectively.

Maybe this design is something that could be fixed as part of https://github.com/detekt/detekt/issues/2680?

arturbosch commented 3 years ago

The gradle plugin does not depend on it but the cli does which we call reflectively.

Maybe this design is something that could be fixed as part of #2680?

We do have this "theoretically" fixed with our new tooling module (even practically in the new experimental https://github.com/detekt/detekt-compiler-plugin). However until Gradle Worker's Api supports classpath caching our hands tied here if we do not want to loose performance.

I have some further documentation in https://github.com/detekt/detekt/pull/2896.