square / okhttp

Square’s meticulous HTTP client for the JVM, Android, and GraalVM.

Home Page:https://square.github.io/okhttp/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

okhttp:5.0.0-alpha.10 can run into `java.lang.ClassNotFoundException: kotlin.time.DurationUnit`

staktrace opened this issue · comments

See previous discussions in #7267, #7329, and #7343. This is a continuation of that thread of problems, trying to iron out issues when using okhttp in a gradle plugin where the runtime kotlin version is restricted to 1.5.

Now I have put together a minimal standalone reproduction of the problem. It can be found at https://github.com/staktrace/20220627-okhttp-durationunit/tree/57afefa7bbe4f1cf1ae0b1dd8b6d4e01c4b738ff. To reproduce, clone the repo and run the ./reproduce.sh script. The setup is that there are two separate gradle projects - one is a plugin that uses okhttp, and the other is a consumer that uses the plugin.

Some things I discovered along the way of creating this reproducer:

  • If the plugin lives in the buildSrc folder of the consumer project, the problem doesn't reproduce
  • The kotlin-dsl plugin being applied is important since it seems to be the thing that actually pins the gradle version to 1.5.31.

For the cases I care about, I was able to work around this issue by doing this - adding the kotlin 1.6 jvm plugin to the consumer repo made the DurationUnit class available and everything worked fine. In a bunch of cases the consumer already had the kotlin-dsl plugin which I had to replace with kotlin("jvm") instead, but this effectively solved all the problems I was seeing in downstream projects.

@staktrace do you still have that repro repo?

The repro is linked in the top comment - https://github.com/staktrace/20220627-okhttp-durationunit (main branch)

@staktrace is it private?

Ah sorry! Yes, it was private. Made it public now.

I'm a bi confused, so want to kick off the discussion of whether this is still needed?

I think this gradle/gradle#19539

and this gradle/gradle#16345, discussed here https://twitter.com/martinbonnin/status/1550035276604522498

Mean that we can revert this. So suggest that we do, I'll put a PR up and compile against 1.6.21.

Or is this the issue? gradle/gradle#19568

Gradle 7.5 will ship with Kotlin 1.6.21 but still target language/api 1/4 for backwards compatibility reasons. This can only be changed in a major version, next one being Gradle 8.0.

Your test PR, with 7.6 works. So going to revert this!

Can you try gradle 7.6 snapshot, or 7.5 release with an older version that you previously had problems with?

I tried your reproducer with the following and it appears to work

implementation("com.squareup.okhttp3:okhttp:5.0.0-alpha.8")

If the plugin lives in the buildSrc folder of the consumer project, the problem doesn't reproduce

Got curious and made a small test there https://github.com/martinbonnin/classloaders. Looks like the dependencies of buildSrc are also put in the classpath albeit with a lower precedence than the embedded Kotlin jar. This way, you effectively end up with 2 versions of kotlin-stdlib on the classpath. So kotlin-stdlib symbols will resolve to the 1.5.31 version, except those that are not present that will fallback and load from the 1.6.10 jar. Gradle classloaders never cease to amaze 🙃 .

In all cases, Gradle 7.5 will fix the issue as it will put 1.6.something by default and this one has DurationUnit available.

@martinbonnin sounds like you agree we can revert the existing attempts and ask people to upgrade to 7.5?

Yep, users that want to use OkHttp in Gradle plugin should be able to do so with Gradle 7.5. Maybe you could add a runtime check when building a new client to point to this issue or give an actionable error message?

I know OkHttp already understands Android vs JVM platforms, but doing so for a build system seems a step too far.

Yup, that's fair 👍

I also confirmed that the original problem I was seeing goes away with gradle 7.5. So 👍 from me for reverting all the things.