Build: upgrade to Gradle 9 + AGP 8.7.2#1270
Conversation
WalkthroughUpgrades Gradle wrapper to 9.0.0, Android Gradle Plugin to 8.7.2, and toolchains resolver to 1.0.0. Refactors dependency version parsing to semver4j. Adds Android namespaces and removes manifest package attributes. Reworks JarInfer and library-model generator to generate .astubx via Exec tasks and embed into jars during packaging. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Dev as Developer
participant G as Gradle
participant B as baseJar (Jar)
participant C as CLI shadowJar (Jar)
participant E as generate...Astubx (Exec)
participant J as jar (Jar)
participant O as Output JAR
Dev->>G: Run :jar
activate G
G->>B: Build base artifact
B-->>G: base-*.jar
G->>C: Build CLI shaded JAR
C-->>G: *-cli-all.jar
G->>E: Exec java -jar CLI -i base.jar -o *.astubx
E-->>G: generated *.astubx
G->>J: Package JAR with astubx (into provider path)
J-->>O: Published JAR containing astubx
deactivate G
note over E,J: Applied in both:\n- jar-infer/test-java-lib-jarinfer\n- library-model/test-library-model-generator
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Suggested reviewers
✨ Finishing Touches🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
207ee54 to
fa80ffb
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1270 +/- ##
=========================================
Coverage 88.55% 88.55%
Complexity 2431 2431
=========================================
Files 91 91
Lines 8013 8013
Branches 1598 1598
=========================================
Hits 7096 7096
Misses 458 458
Partials 459 459 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
72e3ff4 to
c183145
Compare
This PR implements the following new policy for jobs to run on CI: * We only run the build on the latest LTS JDK version (currently 21) * Run tests on the latest LTS JDK version (the standard `test` task) * Run tests on any older LTS versions supported by the latest version of Error Prone (currently JDK 17) * Test on latest JDK version (currently 24) * Test on oldest supported Error Prone version, on oldest JDK that it supports, only for core NullAway tests (JDK 11, Error Prone 2.14.0) * Test on Linux, Mac, and Windows This is in preparation for updating to Gradle 9 (#1270), which can only run on JDK 17+. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - Chores - Simplified CI: trimmed matrix to macOS and Windows, standardized job names, and unified build/test steps. - Adjusted coverage gating to run on Linux with repository filter. - Removed matrix-based gating for local publishing. - Minor cleanup of formatting and step structure. - Tests - Updated JDK test targets: replaced 21 with 17; 24 remains. - Kept certain JDK-specific tests disabled, aligned with new targets. - Removed a version-specific test exclusion, enabling the affected test to run across versions. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
- Gradle wrapper: 9.0.0 with SHA256
- Root build: bump Android Gradle Plugin to 8.7.2
- Android DSL: add namespace, migrate lintOptions->lint, remove BaseVariant APIs
- Manifests: remove package attributes (AGP 8 requires Gradle namespace)
- Gradle 9 removal of internal APIs: replace org.gradle.util.VersionNumber with local comparator
- Jar post-processing: replace jar.doLast { javaexec/exec } with Exec tasks and java -jar
- settings.gradle: always include all modules (removed wrapper guard)
Note: Build succeeds; some tests in integration modules may still fail and will be handled separately.
c183145 to
b6092f5
Compare
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (10)
jar-infer/nullaway-integration-test/build.gradle (1)
37-39: Prefer lazy, type-safe cross-project task wiringUsing a string task path works, but prefer a lazy reference to avoid accidental eager realization and catch renames at compile time.
-tasks.withType(Test).configureEach { - dependsOn(":jar-infer:test-java-lib-jarinfer:embedAstubxIntoJar") -} +tasks.withType(Test).configureEach { + dependsOn(project(":jar-infer:test-java-lib-jarinfer").tasks.named("embedAstubxIntoJar")) +}jar-infer/test-android-lib-jarinfer/build.gradle (1)
20-25: Consider bumping SDK levels used via deps.build to modern values.This module still inherits compile/target SDK 30 from gradle/dependencies.gradle; AGP 8.7 supports API up to 35 and expects Build Tools 34.0.0. Suggest raising compile/target SDK to ≥34 to avoid tooling incompatibilities. (developer.android.com)
gradle/dependencies.gradle (3)
17-23: Avoid adding buildscript classpath from an applied script; prefer build-logic or a tiny local comparator.Adding semver4j via buildscript in a shared Gradle script can hurt configuration cache and complicate classpath resolution. Either:
- move this to buildSrc/precompiled plugin, or
- replace with a small inlined comparator (split on dots, compare ints/prerelease), avoiding extra dependencies.
32-45: Harden epApiVersion parsing error path.Wrap Semver parsing in try/catch and throw a clear IllegalArgumentException when the property isn’t valid semver (even in LOOSE mode), to improve DX.
- def requested = parseSemver(epApiVersion) + def requested + try { + requested = parseSemver(epApiVersion) + } catch (Throwable t) { + throw new IllegalArgumentException("Invalid epApiVersion: '${epApiVersion}'. Expected a semantic version.", t) + }
99-105: Android SDK constants are outdated for AGP 8.7.These drive compile/target/min across modules. Consider:
- compileSdkVersion: 34 or 35
- targetSdkVersion: 34 or 35
Keep minSdk as-is if tests require. (developer.android.com)jar-infer/test-java-lib-jarinfer/build.gradle (3)
57-59: Finalize/dependency wiring can be simplified.With the Jar task including the file, you can drop finalizedBy chains and just dependOn generateJarInferAstubx inside jar.
-jar.finalizedBy generateJarInferAstubx -generateJarInferAstubx.configure { finalizedBy embedAstubxIntoJar } +// handled in jar {} above
67-67: Duplicate dependency on CLI assemble.This duplicates the dependsOn already present in generateJarInferAstubx; safe to remove.
-jar.dependsOn ":jar-infer:jar-infer-cli:assemble" +// redundant; removed
41-43: Hardcoded CLI JAR path may drift.If the CLI jar name includes version/classifier, this path will break. Consider resolving the artifact from the CLI project’s configurations or expose a dedicated configuration/Outgoing artifact.
library-model/test-library-model-generator/build.gradle (1)
54-56: Finalize chain is OK; consider removing redundant jar.dependsOn at Line 64.With the above dependsOn/finalizedBy wiring, the extra “jar.dependsOn ':library-model:library-model-generator-cli:assemble'” (Line 64) is redundant. Drop it to reduce configuration work.
library-model/library-model-generator-integration-test/build.gradle (1)
35-37: Good safeguard to ensure embedding runs before tests.Depending on “:library-model:test-library-model-generator:embedLibModelsAstubxIntoJar” guarantees the JAR is updated pre-test. Optionally, depend on that project’s “jar” task and wire embedding via the Jar task (as suggested in the other file) to avoid cross-project Exec execution from tests.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (13)
build.gradle(1 hunks)gradle/dependencies.gradle(2 hunks)gradle/wrapper/gradle-wrapper.properties(1 hunks)jar-infer/nullaway-integration-test/build.gradle(1 hunks)jar-infer/test-android-lib-jarinfer/build.gradle(1 hunks)jar-infer/test-android-lib-jarinfer/src/main/AndroidManifest.xml(1 hunks)jar-infer/test-java-lib-jarinfer/build.gradle(1 hunks)library-model/library-model-generator-integration-test/build.gradle(1 hunks)library-model/test-library-model-generator/build.gradle(1 hunks)sample-app/build.gradle(3 hunks)sample-app/src/main/AndroidManifest.xml(2 hunks)sample-app/src/main/java/com/uber/myapplication/MainActivity.java(1 hunks)settings.gradle(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Build and test on windows-latest
- GitHub Check: Build caffeine with snapshot
- GitHub Check: Build and test on ubuntu-latest
- GitHub Check: Build and test on macos-latest
🔇 Additional comments (12)
build.gradle (1)
25-25: Remove outdated compatibility warning: Android Gradle Plugin 8.7.2 meets Gradle 9.0.0’s minimum AGP requirement (8.4.0) and is officially supported with Gradle 9.0.0 (docs.gradle.org)Likely an incorrect or invalid review comment.
sample-app/src/main/java/com/uber/myapplication/MainActivity.java (1)
36-36: No-op comment tweak — fine to keepThis is purely a comment change; no runtime effect.
settings.gradle (1)
11-11: Good: foojay resolver 1.0.0 is Gradle 9–readyVersion 1.0.0 explicitly preps for Gradle 9 and requires JDK 17+, which aligns with this repo. No action needed.
Reference: Plugin page notes “prepare for Gradle 9 compatibility.” (plugins.gradle.org)
jar-infer/test-android-lib-jarinfer/src/main/AndroidManifest.xml (1)
1-1: Confirmed: all AndroidManifests omitpackageand every module declaresnamespace
Nopackage=attributes remain in any AndroidManifest.xml, and all Gradle modules using AGP plugins include an explicitnamespacesetting.jar-infer/test-android-lib-jarinfer/build.gradle (1)
21-21: Namespace addition is correct for AGP 8+; LGTM.Switching from manifest package to Gradle namespace is the right move. Relative component names (like ".FooActivity") resolve against this namespace. (developer.android.com)
gradle/wrapper/gradle-wrapper.properties (2)
3-4: Gradle 9.0.0 upgrade: ensure JDK ≥17 in CI and AGP compatibility.
- Gradle 9 requires Java 17+ to run. Verify CI/toolchains use JDK 17 or newer. (docs.gradle.org, fossies.org)
- Gradle 9’s minimum supported AGP is 8.4; your build uses AGP 8.7, which satisfies this. (docs.gradle.org)
- AGP 8.7’s documented minimum Gradle is 8.9; running on 9.0 is typically fine but not explicitly listed—smoke test recommended. (developer.android.com)
3-4: Double-check wrapper SHA and regenerate via wrapper task.Confirm the SHA256 matches services.gradle.org for 9.0.0 and that gradlew/gradlew.bat were refreshed with the wrapper task.
sample-app/src/main/AndroidManifest.xml (1)
2-3: Package removal is correct; dot-prefixed Activity names still resolve.With AGP 8+, use Gradle namespace and omit manifest package; ".MainActivity" resolves against the module’s namespace. (developer.android.com)
gradle/dependencies.gradle (2)
47-63: Version map updates look fine.Switch to semver4j doesn’t affect the constants here; values compile. Noting gson 2.13.1 is valid. (mvnrepository.com, google.github.io)
74-85: Gradle 9 removes org.gradle.util.VersionNumber; your replacement approach is correct.Semver-based comparison is an appropriate substitute. (docs.gradle.org)
sample-app/build.gradle (2)
25-25: Namespace addition for AGP 8+ is correct.
39-41: Lint DSL migration looks good.
| def generateJarInferAstubx = tasks.register('generateJarInferAstubx', Exec) { | ||
| dependsOn ":jar-infer:jar-infer-cli:assemble" | ||
| dependsOn jar | ||
| doFirst { | ||
| commandLine "java", | ||
| "-jar", | ||
| "${rootProject.projectDir}/jar-infer/jar-infer-cli/build/libs/jar-infer-cli.jar", | ||
| "-i", | ||
| jar.archiveFile.get().asFile.absolutePath, | ||
| "-o", | ||
| "${jar.destinationDirectory.get()}/${astubxPath}" | ||
| } | ||
| exec { | ||
| workingDir "./build/libs" | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Use toolchains and declare inputs/outputs for reproducible, cacheable execution.
- Exec with bare "java" depends on PATH; use JavaToolchainService to locate a JDK 17+ launcher.
- Declare inputs (the jar) and outputs (the .astubx) so the task can be up-to-date/cached.
def generateJarInferAstubx = tasks.register('generateJarInferAstubx', Exec) {
dependsOn ":jar-infer:jar-infer-cli:assemble"
dependsOn jar
+ // cacheability
+ inputs.file(jar.archiveFile)
+ outputs.file(layout.buildDirectory.file("generated/jarinfer/${astubxPath}"))
doFirst {
- commandLine "java",
+ // resolve java via toolchains for stability
+ def launcher = project.extensions.findByType(org.gradle.jvm.toolchain.JavaToolchainService)
+ .launcherFor { languageVersion = JavaLanguageVersion.of(17) }.get()
+ commandLine launcher.executablePath.asFile.absolutePath,
"-jar",
"${rootProject.projectDir}/jar-infer/jar-infer-cli/build/libs/jar-infer-cli.jar",
"-i",
jar.archiveFile.get().asFile.absolutePath,
"-o",
- "${jar.destinationDirectory.get()}/${astubxPath}"
+ layout.buildDirectory.file("generated/jarinfer/${astubxPath}").get().asFile.absolutePath
}
}🤖 Prompt for AI Agents
In jar-infer/test-java-lib-jarinfer/build.gradle around lines 35 to 47, the Exec
task uses a bare "java" and doesn't declare task inputs/outputs; change it to
obtain a Java 17+ launcher via the JavaToolchainService (e.g., request a
launcher for JavaLanguageVersion.of(17)) and use that launcher's executable path
instead of the plain "java" string, and declare inputs.file pointing to
jar.archiveFile and outputs.file pointing to the generated
"${jar.destinationDirectory.get()}/${astubxPath}" so Gradle can determine
up-to-date/caching behavior; keep the commandLine invocation but set the
executable from the toolchain launcher and add proper inputs/outputs to the task
configuration.
| def generateLibModelsAstubx = tasks.register('generateLibModelsAstubx', Exec) { | ||
| dependsOn ":library-model:library-model-generator-cli:assemble" | ||
| dependsOn jar | ||
| doFirst { | ||
| commandLine "java", | ||
| "-jar", | ||
| "${rootProject.projectDir}/library-model/library-model-generator-cli/build/libs/library-model-generator-cli.jar", | ||
| testInputsPath, | ||
| "${jar.destinationDirectory.get()}/${astubxPath}" | ||
| } | ||
| exec { | ||
| workingDir "./build/libs" | ||
| } | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion
Avoid hard-coded CLI JAR path; add task inputs/outputs for incrementality.
The Exec uses a fixed path to library-model-generator-cli.jar, which will break if the jar is versioned or renamed. Also, the task has no declared inputs/outputs, so it won’t be up-to-date/cacheable.
Suggested fix: derive the CLI jar from the producer task and declare inputs/outputs.
-def generateLibModelsAstubx = tasks.register('generateLibModelsAstubx', Exec) {
- dependsOn ":library-model:library-model-generator-cli:assemble"
- dependsOn jar
- doFirst {
- commandLine "java",
- "-jar",
- "${rootProject.projectDir}/library-model/library-model-generator-cli/build/libs/library-model-generator-cli.jar",
- testInputsPath,
- "${jar.destinationDirectory.get()}/${astubxPath}"
- }
-}
+def cliJar = project(":library-model:library-model-generator-cli")
+ .tasks.named("jar", Jar)
+ .flatMap { it.archiveFile }
+
+def generateLibModelsAstubx = tasks.register('generateLibModelsAstubx', Exec) {
+ dependsOn cliJar.map { it.asFile } // ensures producer jar is built
+ dependsOn jar
+ inputs.dir(testInputsPath)
+ outputs.file(layout.buildDirectory.file("libs/${astubxPath}"))
+ doFirst {
+ commandLine "java",
+ "-jar",
+ cliJar.get().asFile.absolutePath,
+ testInputsPath,
+ layout.buildDirectory.file("libs/${astubxPath}").get().asFile.absolutePath
+ }
+}🤖 Prompt for AI Agents
In library-model/test-library-model-generator/build.gradle around lines 34 to
45, the Exec task hard-codes the CLI jar path and has no declared
inputs/outputs; change it to derive the CLI jar from the producer project's jar
task (use the
project(':library-model:library-model-generator-cli').tasks.named('jar')
archiveFile provider) and use that provider when building the command line, and
declare task inputs (the CLI archiveFile and testInputsPath) and outputs (the
generated astubx output file) so Gradle can properly track up-to-dateness and
caching.
| def embedLibModelsAstubxIntoJar = tasks.register('embedLibModelsAstubxIntoJar', Exec) { | ||
| dependsOn generateLibModelsAstubx | ||
| workingDir "${buildDir}/libs" | ||
| doFirst { | ||
| commandLine "jar", "uf", "test-library-model-generator.jar", astubxPath | ||
| } | ||
| } | ||
|
|
||
| jar.finalizedBy generateLibModelsAstubx | ||
| generateLibModelsAstubx.configure { finalizedBy embedLibModelsAstubxIntoJar } | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion
Prefer wiring generated file into the Jar task instead of shelling out to “jar uf”.
Invoking the external “jar” tool is brittle (PATH/toolchain dependent), non-incremental, and not configuration-cache friendly. Have the Jar task include the generated file instead.
Minimal change if you keep this task: at least declare inputs/outputs and use jar.destinationDirectory to avoid hard-coded build paths.
-def embedLibModelsAstubxIntoJar = tasks.register('embedLibModelsAstubxIntoJar', Exec) {
- dependsOn generateLibModelsAstubx
- workingDir "${buildDir}/libs"
- doFirst {
- commandLine "jar", "uf", "test-library-model-generator.jar", astubxPath
- }
-}
+def embedLibModelsAstubxIntoJar = tasks.register('embedLibModelsAstubxIntoJar', Exec) {
+ dependsOn generateLibModelsAstubx
+ inputs.files(jar.flatMap { it.archiveFile }, layout.buildDirectory.file("libs/${astubxPath}"))
+ outputs.file(jar.flatMap { it.archiveFile })
+ doFirst {
+ workingDir(jar.get().destinationDirectory.get().asFile)
+ commandLine "jar", "uf", jar.get().archiveFile.get().asFile.name, astubxPath
+ }
+}Preferred alternative (no external exec, incremental):
-jar.finalizedBy generateLibModelsAstubx
-generateLibModelsAstubx.configure { finalizedBy embedLibModelsAstubxIntoJar }
+tasks.named("jar", Jar).configure {
+ dependsOn(generateLibModelsAstubx)
+ from(layout.buildDirectory.file("libs/${astubxPath}")) {
+ into "com/uber/nullaway/libmodel/provider"
+ }
+}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| def embedLibModelsAstubxIntoJar = tasks.register('embedLibModelsAstubxIntoJar', Exec) { | |
| dependsOn generateLibModelsAstubx | |
| workingDir "${buildDir}/libs" | |
| doFirst { | |
| commandLine "jar", "uf", "test-library-model-generator.jar", astubxPath | |
| } | |
| } | |
| jar.finalizedBy generateLibModelsAstubx | |
| generateLibModelsAstubx.configure { finalizedBy embedLibModelsAstubxIntoJar } | |
| def embedLibModelsAstubxIntoJar = tasks.register('embedLibModelsAstubxIntoJar', Exec) { | |
| dependsOn generateLibModelsAstubx | |
| inputs.files(jar.flatMap { it.archiveFile }, layout.buildDirectory.file("libs/${astubxPath}")) | |
| outputs.file(jar.flatMap { it.archiveFile }) | |
| doFirst { | |
| workingDir(jar.get().destinationDirectory.get().asFile) | |
| commandLine "jar", "uf", jar.get().archiveFile.get().asFile.name, astubxPath | |
| } | |
| } | |
| jar.finalizedBy generateLibModelsAstubx | |
| generateLibModelsAstubx.configure { finalizedBy embedLibModelsAstubxIntoJar } |
🤖 Prompt for AI Agents
In library-model/test-library-model-generator/build.gradle around lines 46–56,
replace the Exec task that shells out to "jar uf" with wiring the generated file
into the existing Jar task: stop calling the external jar tool, make
generateLibModelsAstubx declare its produced file as an output (and its inputs),
have the Jar task dependOn generateLibModelsAstubx and include the generated
file via the jar task's from/configuration (or point jar to
jar.destinationDirectory rather than hard-coding build paths), and if you keep
an auxiliary task ensure it declares proper inputs/outputs and does not rely on
hard-coded ${buildDir}/libs paths so the operation is incremental and
configuration-cache friendly.
| // Configure Java compilation for all Android JavaCompile tasks (AGP 8+ compatible) | ||
| tasks.withType(JavaCompile).configureEach { | ||
| options.compilerArgs += [ | ||
| "-XDcompilePolicy=simple", | ||
| "--should-stop=ifError=FLOW", | ||
| "-Xplugin:ErrorProne -XepOpt:NullAway:AnnotatedPackages=com.uber", | ||
| ] | ||
| options.fork = true | ||
| options.forkOptions.jvmArgs = [ | ||
| "--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", | ||
| "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", | ||
| "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", | ||
| "--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED", | ||
| "--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED", | ||
| "--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED", | ||
| "--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", | ||
| "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", | ||
| "--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED", | ||
| "--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED" | ||
| ] | ||
| } |
There was a problem hiding this comment.
Fix Error Prone/NullAway args: split tokens and enable the check.
Currently the two flags are concatenated into one token, so javac won’t recognize them. Also, NullAway isn’t enabled unless you add “-Xep:NullAway:ERROR”.
tasks.withType(JavaCompile).configureEach {
- options.compilerArgs += [
- "-XDcompilePolicy=simple",
- "--should-stop=ifError=FLOW",
- "-Xplugin:ErrorProne -XepOpt:NullAway:AnnotatedPackages=com.uber",
- ]
+ options.compilerArgs += [
+ "-XDcompilePolicy=simple",
+ "--should-stop=ifError=FLOW",
+ "-Xplugin:ErrorProne",
+ "-Xep:NullAway:ERROR",
+ "-XepOpt:NullAway:AnnotatedPackages=com.uber",
+ ]
options.fork = true
options.forkOptions.jvmArgs = [
"--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED",
"--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED",
"--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED",
"--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED",
"--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED",
"--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED",
"--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
"--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
"--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
"--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED"
]
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Configure Java compilation for all Android JavaCompile tasks (AGP 8+ compatible) | |
| tasks.withType(JavaCompile).configureEach { | |
| options.compilerArgs += [ | |
| "-XDcompilePolicy=simple", | |
| "--should-stop=ifError=FLOW", | |
| "-Xplugin:ErrorProne -XepOpt:NullAway:AnnotatedPackages=com.uber", | |
| ] | |
| options.fork = true | |
| options.forkOptions.jvmArgs = [ | |
| "--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", | |
| "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", | |
| "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", | |
| "--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED", | |
| "--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED", | |
| "--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED", | |
| "--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", | |
| "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", | |
| "--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED", | |
| "--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED" | |
| ] | |
| } | |
| tasks.withType(JavaCompile).configureEach { | |
| options.compilerArgs += [ | |
| "-XDcompilePolicy=simple", | |
| "--should-stop=ifError=FLOW", | |
| "-Xplugin:ErrorProne", | |
| "-Xep:NullAway:ERROR", | |
| "-XepOpt:NullAway:AnnotatedPackages=com.uber", | |
| ] | |
| options.fork = true | |
| options.forkOptions.jvmArgs = [ | |
| "--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", | |
| "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", | |
| "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", | |
| "--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED", | |
| "--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED", | |
| "--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED", | |
| "--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", | |
| "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", | |
| "--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED", | |
| "--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED" | |
| ] | |
| } |
🤖 Prompt for AI Agents
In sample-app/build.gradle around lines 53 to 73, the ErrorProne/NullAway JVM
compiler args are combined into a single token so javac won’t parse them; split
the concatenated string into separate compiler argument tokens (e.g.
"-Xplugin:ErrorProne" and "-XepOpt:NullAway:AnnotatedPackages=com.uber" as two
entries) and add the NullAway enforcement flag "-Xep:NullAway:ERROR" as its own
token so NullAway is enabled as an error.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (2)
jar-infer/test-java-lib-jarinfer/build.gradle (2)
42-51: Use Java Toolchains for a cross-platform, reproducible launcher (Windows-safe).System.getProperty("java.home")/bin/java can be brittle on Windows and divorces the build from toolchains. Prefer a JavaLauncher from JavaToolchainService and set executable/args.
- doFirst { - // use the same java as Gradle itself - def javaBin = new File(System.getProperty("java.home"), "bin/java") - - commandLine javaBin.absolutePath, - "-jar", - jarInferCliJar.get().asFile.absolutePath, - "-i", baseJarFile.get().asFile.absolutePath, - "-o", outputAstubxFile.get().asFile.absolutePath - } + doFirst { + def toolchains = project.extensions.getByType(org.gradle.jvm.toolchain.JavaToolchainService) + // Pick the version your CLI targets (17 is a common baseline) + def launcher = toolchains.launcherFor { languageVersion = JavaLanguageVersion.of(17) }.get() + executable = launcher.executablePath.asFile.absolutePath + args "-jar", + jarInferCliJar.get().asFile.absolutePath, + "-i", baseJarFile.get().asFile.absolutePath, + "-o", outputAstubxFile.get().asFile.absolutePath + }
62-64: Good: embed via Jar task instead of post-processing.dependsOn + from(...)/into(...) is the right, cacheable approach; avoids “jar uf” mutations.
🧹 Nitpick comments (2)
jar-infer/test-java-lib-jarinfer/build.gradle (2)
28-34: Avoid hard dependency on ShadowJar type to reduce classpath coupling.Referencing com.github.jengelman...ShadowJar here can break if the plugin isn’t on this project’s script classpath. Use an untyped TaskProvider and cast at usage.
-def shadowJarTask = cliProj.tasks.named( - "shadowJar", - com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar - ) -def jarInferCliJar = shadowJarTask.flatMap { it.archiveFile } +def shadowJarTask = cliProj.tasks.named("shadowJar") +def jarInferCliJar = shadowJarTask.flatMap { (it as org.gradle.api.tasks.bundling.AbstractArchiveTask).archiveFile }
57-59: Optional: remove volatile manifest fields to improve reproducibility.Build-Jdk and Build-OS vary across machines and reduce artifact reproducibility. Consider dropping them or gating behind a flag.
attributes( - 'Created-By' : "Gradle ${gradle.gradleVersion}", - 'Build-Jdk' : "${System.properties['java.version']} (${System.properties['java.vendor']} ${System.properties['java.vm.version']})", - 'Build-OS' : "${System.properties['os.name']} ${System.properties['os.arch']} ${System.properties['os.version']}" + 'Created-By' : "Gradle ${gradle.gradleVersion}" )
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
jar-infer/test-java-lib-jarinfer/build.gradle(1 hunks)library-model/test-library-model-generator/build.gradle(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- library-model/test-library-model-generator/build.gradle
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: Build and test on macos-latest
- GitHub Check: Build and test on ubuntu-latest
- GitHub Check: Build caffeine with snapshot
- GitHub Check: Build and test on windows-latest
- GitHub Check: Build spring-framework with snapshot
🔇 Additional comments (3)
jar-infer/test-java-lib-jarinfer/build.gradle (3)
21-21: LGTM: deterministic, lazily-evaluated output location.Using layout.buildDirectory with a Provider keeps configuration lazy and cache-friendly.
23-26: Base JAR task looks good.Isolating a “base” archive for analysis avoids mutating the main jar and keeps inputs stable.
38-41: Nice: proper inputs/outputs declared for caching.Declaring baseJar and CLI jar as inputs and the astubx as an output enables up-to-date checks and build cache.
Summary by CodeRabbit