okhttp
okhttp copied to clipboard
v5.0.0-alpha16 - No virtual method getEventListenerFactory
After updating from v5.0.0-alpha14 to v5.0.0-alpha16, the release build of my android app is crashing with the following error:
NoSuchMethodError: No virtual method getEventListenerFactory$okhttp()Lokhttp3/EventListener$Factory; in class LJf/K; or its super classes (declaration of 'Jf.K' appears in /data/app/~~F8MgBq3JZu9FbBw49qQ8DQ==/com.myapp.release-N05Wr0CV4hKEqlty98x18g==/base.apk)
This works fine using debug builds, so likely an R8 issue if I have to guess.
I get that on debug builds too
Do you have a simple repro? Is it relatively recent Gradle, AGP etc?
I don't have a repo, but I'm using gradle 8.14.1, kotlin 2.1.21, AGP 8.10.1. The project is also using wire (5.3.1) and retrofit (3.0.0).
Yep, that seems quite modern.
I'll try to make a simple repro next week with a debug and release build and if I can't maybe get you to see what differs.
Using com.squareup.okhttp3:okhttp-jvm instead of com.squareup.okhttp3:okhttp solved it for me, see https://github.com/square/okhttp/blob/master/CHANGELOG.md#version-500-alpha15
That should be handled automatically for an android Gradle build or I assume maven.
Also if you need this workaround, make sure to use the android artifact on android builds
Using
com.squareup.okhttp3:okhttp-jvminstead ofcom.squareup.okhttp3:okhttpsolved it for me, see https://github.com/square/okhttp/blob/master/CHANGELOG.md#version-500-alpha15
I don't believe this is a workaround I want to consider given that I really want to use the android artifact, not just the jvm.
I don't have an interesting repro, mainly because I can't get it failing with a debug or release build. or with the OkHttp android test app.
@Singleton
@Provides
fun okhttpClient(
cache: Cache,
alwaysHttpsInterceptor: Interceptor,
): OkHttpClient {
return OkHttpClient.Builder().followSslRedirects(false)
.addInterceptor(alwaysHttpsInterceptor)
.eventListenerFactory(LoggingEventListener.Factory())
.cache(cache)
.build()
.apply { println("Using okhttp client " + this.eventListenerFactory) }
}
Using okhttp client A3.e@b4f5a98
Can anyone provide a repro github project?
I don't have an interesting repro, mainly because I can't get it failing with a debug or release build. or with the OkHttp android test app.
@Singleton @Provides fun okhttpClient( cache: Cache, alwaysHttpsInterceptor: Interceptor, ): OkHttpClient { return OkHttpClient.Builder().followSslRedirects(false) .addInterceptor(alwaysHttpsInterceptor) .eventListenerFactory(LoggingEventListener.Factory()) .cache(cache) .build() .apply { println("Using okhttp client " + this.eventListenerFactory) } }Using okhttp client A3.e@b4f5a98Can anyone provide a repro github project?
I don't use the eventListenerFactory directly, for example:
OkHttpClient.Builder().run {
addDefaultHeadersInterceptor() // attaches certain headers to every request
addDebugInterceptor() // used for logging responses in debug builds
build()
}
I will try to create a sample project in the next two weeks.
@yschimke I did a bit more testing and I exclude all okhttp from my r8 rules and getting this full error:
java.lang.NoSuchMethodError: No virtual method getEventListenerFactory$okhttp()Lokhttp3/EventListener$Factory; in class Lokhttp3/OkHttpClient$Builder; or its super classes
Is there maybe a version conflict between retrofit, wire and okhttp?
Can you include full stacktraces?
Found the version conflict. LaunchDarkly seems to be causing issues with the latest alpha.
FATAL EXCEPTION: DefaultDispatcher-worker-1
Process: com.myapp, PID: 7485
java.lang.NoSuchMethodError: No virtual method getEventListenerFactory$okhttp()Lokhttp3/EventListener$Factory; in class Lokhttp3/OkHttpClient$Builder; or its super classes (declaration of 'okhttp3.OkHttpClient$Builder' appears in /data/app/~~HV1pzQaz2377sonUaOdLcQ==/com.myapp-1CWGCF1gGfQMzEHXGhCyCA==/base.apk!classes2.dex)
at okhttp3.OkHttpClient.
I don't think that points to LaunchDarkly. It says the initializer of OkHttpClient is trying to access a method on OkHttpClient$Builder which doesn't exist. This likely means you have two copies of OkHttp on your classpath and you are getting an OkHttpClient.class from one and OkHttpClient$Builder.class from the other, and they disagree on version.
Thanks for your suggestion. I verified that I've got all my okhttp3 versions the same but the crash is still happening.
You would have to check the runtime classpath of the dependencies task to see if there are multiple copies. Since OkHttp switched to being multiplatform, you could have something like okhttp-4.12.0.jar and okhttp-jvm-5.0.0-alpha16.jar both present, since the latter imposes no dependency constraint on the former.
I believe that will be the outcome of this bug, is the addition of a dependency constraint to ensure the "common" artifact has a version which matches the target-specific dependency.
I have added
subprojects {
configurations.all {
resolutionStrategy {
force("com.squareup.okhttp3:okhttp:5.0.0-alpha.16")
}
}
}
to my root build.gradle.kts file and verified that there is just alpha16 mentioned when checking the runtime classpath.
@AlexanderEggers did this help you?
I still get java.lang.NoSuchMethodError: No virtual method getEventListenerFactory$okhttp()Lokhttp3/EventListener$Factory; in class Lokhttp3/OkHttpClient$Builder; or its super classes when OkHttpClient.Builder().build() is called.
Unfortunately no, I'm still having the same issue.
Can you run and post the output
./gradlew app:dependencies
On this branch I’ve attempted a few combinations of OkHttp-including transitive dependencies:
- LaunchDarkly, because it‘s mentioned here
- Wire, because it is a multiplatform library that depends on OkHttp
- Retrofit, because it is a non-multiplatform library that depends on OkHttp And target platforms:
- Java
- Android
Thus far I haven’t been able to reproduce this problem.
I would greatly appreciate some help reproducing this problem. I would like to fix this before releasing 5.0 final!
On this commit, Gradle 8.10.1 resolved the right okhttp-android artifact, and only that one. I wonder what else I’m missing..
releaseRuntimeClasspath - Runtime classpath of '/release'.
+--- org.jetbrains.kotlin:kotlin-stdlib:2.1.21
| \--- org.jetbrains:annotations:13.0 -> 23.0.0
+--- com.launchdarkly:launchdarkly-android-client-sdk:5.0.0
| +--- com.google.code.gson:gson:2.8.9
| +--- androidx.annotation:annotation:1.2.0 -> 1.9.1
| | \--- androidx.annotation:annotation-jvm:1.9.1
| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.1.21 (*)
| +--- com.launchdarkly:launchdarkly-java-sdk-internal:1.0.0
| | +--- com.google.code.gson:gson:2.8.9
| | +--- com.launchdarkly:launchdarkly-java-sdk-common:2.0.0 -> 2.1.0
| | +--- com.launchdarkly:launchdarkly-logging:1.1.1
| | \--- com.squareup.okhttp3:okhttp:4.9.1 -> 5.0.0-alpha.16
| | \--- com.squareup.okhttp3:okhttp-android:5.0.0-alpha.16
| | +--- androidx.annotation:annotation:1.9.1 (*)
| | +--- androidx.startup:startup-runtime:1.2.0
| | | +--- androidx.annotation:annotation:1.8.1 -> 1.9.1 (*)
| | | \--- androidx.tracing:tracing:1.0.0
| | | \--- androidx.annotation:annotation:1.1.0 -> 1.9.1 (*)
| | +--- com.squareup.okio:okio:3.12.0
| | | \--- com.squareup.okio:okio-jvm:3.12.0
| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.1.21 (*)
| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.1.21 (*)
| +--- com.launchdarkly:okhttp-eventsource:3.0.0
| | +--- com.launchdarkly:launchdarkly-logging:1.1.1
| | \--- com.squareup.okhttp3:okhttp:4.9.3 -> 5.0.0-alpha.16 (*)
| +--- com.squareup.okhttp3:okhttp:4.9.2 -> 5.0.0-alpha.16 (*)
| +--- com.jakewharton.timber:timber:5.0.1
| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.21 -> 2.1.21 (*)
| | \--- org.jetbrains:annotations:20.1.0 -> 23.0.0
| +--- com.launchdarkly:launchdarkly-java-sdk-common:2.1.0
| \--- com.launchdarkly:launchdarkly-logging:1.1.1
+--- com.squareup.retrofit2:retrofit:3.0.0
| +--- com.squareup.okhttp3:okhttp:4.12.0 -> 5.0.0-alpha.16 (*)
| \--- org.jetbrains.kotlin:kotlin-stdlib:2.1.21 (*)
+--- com.squareup.wire:wire-grpc-client:5.3.3
| \--- com.squareup.wire:wire-grpc-client-jvm:5.3.3
| +--- com.squareup.okhttp3:okhttp:5.0.0-alpha.14 -> 5.0.0-alpha.16 (*)
| +--- com.squareup.wire:wire-runtime:5.3.3
| | \--- com.squareup.wire:wire-runtime-jvm:5.3.3
| | +--- com.squareup.okio:okio:3.9.1 -> 3.12.0 (*)
| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.21 -> 2.1.21 (*)
| +--- com.squareup.okio:okio:3.9.1 -> 3.12.0 (*)
| +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0
| | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0
| | +--- org.jetbrains:annotations:23.0.0
| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0
| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0 (c)
| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (c)
| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.1.21 (*)
| \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.21 -> 2.1.21 (*)
\--- project :lib-depends-on-latest
+--- com.squareup.okhttp3:okhttp:5.0.0-alpha.16 (*)
\--- org.jetbrains.kotlin:kotlin-stdlib:2.1.21 (*)
Is it possible some apps are depending on okhttp-android directly. If that's above the okhttp version, could it cause this?
./gradlew app:dependencies
@yschimke I've attached a file after running this command for one of my release configurations. I just modified some of the naming but I hope that file still makes sense.
Let me know if I need to generate that output differently.
@AlexanderEggers That all looks correct. Everything* okhttp being bumped to to 5.0.0-alpha.16
And okhttp pulling in okhttp-android
| +--- com.launchdarkly:okhttp-eventsource:3.0.0
| | +--- com.launchdarkly:launchdarkly-logging:1.1.1
| | \--- com.squareup.okhttp3:okhttp:4.9.3 -> 5.0.0-alpha.16 (*)
...
| | | +--- com.squareup.retrofit2:retrofit:3.0.0
| | | | +--- com.squareup.okhttp3:okhttp:4.12.0 -> 5.0.0-alpha.16 (*)
...
| | | | | | \--- com.squareup.wire:wire-grpc-client-jvm:5.3.3
| | | | | | +--- com.squareup.okhttp3:okhttp:5.0.0-alpha.14 -> 5.0.0-alpha.16 (*)
...
| \--- com.squareup.okhttp3:okhttp:5.0.0-alpha.16
| +--- com.squareup.okhttp3:okhttp-android:5.0.0-alpha.16
You have okhttp 2 - but that's an unrelated package.
| | | \--- com.google.android.libraries.places:places:4.3.1
...
| | | +--- com.squareup.okhttp:okhttp:2.7.2
| | | | \--- com.squareup.okio:okio:1.6.0 -> 3.13.0 (*)
Any ideas which could still cause the issue in the release then? If everything is using the right okhttp3 version, then things should work, right?
Nope, I wonder how to see why R8 strips something. I know you can ask why it's kept.
-whyareyoukeeping <class-spec>
but can you try with something like (I'm bad at these)
-keepclassmembers class okhttp3.OkHttpClient$Builder {
*** getEventListenerFactory*(*);
}
I tried that but it is still crashing in release builds with the same error.
I’m pretty sure this is an R8 problem and not a publishing problem. The missing function is unchanged from OkHttp 4.12 through current:
$ unzip /Users/jwilson/.gradle/caches/modules-2/files-2.1/com.squareup.okhttp3/okhttp/4.12.0/2f4525d4a200e97e1b87449c2cd9bd2e25b7e8cd/okhttp-4.12.0.jar
$ javap okhttp3/OkHttpClient\$Builder.class
...
public final okhttp3.EventListener$Factory getEventListenerFactory$okhttp();
$ unzip /Users/jwilson/.gradle/caches/modules-2/files-2.1/com.squareup.okhttp3/okhttp-jvm/5.0.0-SNAPSHOT/7eccf16d57a375b5fa88257c87b52dd32192f773/okhttp-jvm-5.0.0-SNAPSHOT.jar
$ javap okhttp3/OkHttpClient\$Builder.class
...
public final okhttp3.EventListener$Factory getEventListenerFactory$okhttp();
I'm facing the issue in debug builds without R8
If you can share a repro project, I'm sure we can fix it in a small unit of time. Before the v5.0.0 release.
But without that, I'm not sure what we can do.