From dd9f99e6828068486d013638ef83277fc7a95ab7 Mon Sep 17 00:00:00 2001 From: Yuri Schimke Date: Sat, 25 Jul 2026 23:40:01 +0100 Subject: [PATCH] Share Robolectric JVM setup in a convention plugin Want to avoid running API 37 on JDK 17. Also we already have the add-opens defined, but started to list them again. --- android-test/build.gradle.kts | 17 +------ .../okhttp.robolectric-conventions.gradle.kts | 45 +++++++++++++++++++ okhttp/build.gradle.kts | 15 +------ 3 files changed, 47 insertions(+), 30 deletions(-) create mode 100644 build-logic/src/main/kotlin/okhttp.robolectric-conventions.gradle.kts diff --git a/android-test/build.gradle.kts b/android-test/build.gradle.kts index bc0e5212c78b..d2af2bee97d3 100644 --- a/android-test/build.gradle.kts +++ b/android-test/build.gradle.kts @@ -3,6 +3,7 @@ import okhttp3.buildsupport.androidBuild plugins { id("okhttp.base-conventions") + id("okhttp.robolectric-conventions") id("com.android.library") id("de.mannodermaus.android-junit5") } @@ -43,22 +44,6 @@ android { testOptions { targetSdk = 37 unitTests.isIncludeAndroidResources = true - - // Robolectric 4.17 reflects into JDK internals, which JDK 17+ blocks by default. - // https://robolectric.org/getting-started/ - unitTests.all { - it.jvmArgs( - "--add-opens=java.base/java.lang=ALL-UNNAMED", - "--add-opens=java.base/java.util=ALL-UNNAMED", - "--add-opens=java.base/java.io=ALL-UNNAMED", - "--add-opens=java.base/java.net=ALL-UNNAMED", - "--add-opens=java.base/java.security=ALL-UNNAMED", - "--add-opens=java.base/java.text=ALL-UNNAMED", - "--add-opens=java.base/jdk.internal.access=ALL-UNNAMED", - "--add-opens=java.desktop/java.awt.font=ALL-UNNAMED", - "--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", - ) - } } diff --git a/build-logic/src/main/kotlin/okhttp.robolectric-conventions.gradle.kts b/build-logic/src/main/kotlin/okhttp.robolectric-conventions.gradle.kts new file mode 100644 index 000000000000..3663adc984de --- /dev/null +++ b/build-logic/src/main/kotlin/okhttp.robolectric-conventions.gradle.kts @@ -0,0 +1,45 @@ +import okhttp3.buildsupport.testJavaVersion + +/** + * Shared configuration for the modules that run Robolectric tests. + * + * Robolectric reflects into JDK internals, which JDK 17+ blocks by default, and its newer Android + * images need a newer JVM. https://robolectric.org/getting-started/ + */ + +/** Opened so Robolectric can reflect into the JDK internals its shadows and interceptors use. */ +val robolectricJvmArgs = + listOf( + "--add-opens=java.base/java.lang=ALL-UNNAMED", + "--add-opens=java.base/java.util=ALL-UNNAMED", + "--add-opens=java.base/java.io=ALL-UNNAMED", + "--add-opens=java.base/java.net=ALL-UNNAMED", + "--add-opens=java.base/java.security=ALL-UNNAMED", + "--add-opens=java.base/java.text=ALL-UNNAMED", + "--add-opens=java.base/jdk.internal.access=ALL-UNNAMED", + "--add-opens=java.desktop/java.awt.font=ALL-UNNAMED", + "--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", + ) + +tasks.withType().configureEach { + if (testJavaVersion >= 9) { + jvmArgs(robolectricJvmArgs) + } + + if (testJavaVersion < 21) { + // Robolectric needs Java 21 to sandbox Android SDK 37. Tests configured only for SDKs outside + // this set are skipped rather than failing to create a sandbox. + systemProperty("robolectric.enabledSdks", (21..36).joinToString(",")) + } +} + +if (testJavaVersion < 9) { + afterEvaluate { + tasks.withType { + // Work around robolectric requirements and limitations. The Android Gradle Plugin adds + // --add-opens itself, which Java 8 doesn't understand. + // https://cs.android.com/android-studio/platform/tools/base/+/mirror-goog-studio-main:build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/factory/AndroidUnitTest.java;l=339 + allJvmArgs = allJvmArgs.filter { !it.startsWith("--add-opens") } + } + } +} diff --git a/okhttp/build.gradle.kts b/okhttp/build.gradle.kts index 15d24f092949..44928588ff72 100644 --- a/okhttp/build.gradle.kts +++ b/okhttp/build.gradle.kts @@ -16,6 +16,7 @@ plugins { id("okhttp.jvm-conventions") id("okhttp.quality-conventions") id("okhttp.testing-conventions") + id("okhttp.robolectric-conventions") id("app.cash.burst") alias(libs.plugins.maven.sympathy) } @@ -324,20 +325,6 @@ project.tasks.withType { } } -afterEvaluate { - tasks.withType { - if (javaLauncher - .get() - .metadata.languageVersion - .asInt() < 9 - ) { - // Work around robolectric requirements and limitations - // https://cs.android.com/android-studio/platform/tools/base/+/mirror-goog-studio-main:build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/factory/AndroidUnitTest.java;l=339 - allJvmArgs = allJvmArgs.filter { !it.startsWith("--add-opens") } - } - } -} - // Work around issue 8826, where the Sentry SDK assumes that OkHttp's internal-visibility symbols // will be suffixed '$okhttp' in deployable artifacts. This isn't intended to be a published API, // but it's easy enough for us to keep it working. https://github.com/lysine-dev/okhttp/issues/8826