Skip to content

Enable JSpecify JDK models (under a flag) - #1641

Merged
msridhar merged 26 commits into
masterfrom
jdk-astubx
Jul 24, 2026
Merged

Enable JSpecify JDK models (under a flag)#1641
msridhar merged 26 commits into
masterfrom
jdk-astubx

Conversation

@msridhar

@msridhar msridhar commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

This PR adds an astubx capturing JSpecify JDK models of nullability, and loads and uses those models when a flag is enabled. We enable the flag for checking NullAway itself. The new JDK models can only be used in JSpecify mode, since JSpecify-mode checking is required to not get a lot of false positive warnings.

We also add a basic document on how to run our code to generate the astubx file.

For now, we add a separate flag for loading JDK models from the JarInfer flag. We can consider merging these flags in a follow-up if desirable.

Some changes in this PR fix new NullAway warnings that are due to the new models. I could try to split out those changes into a separate PR, but they're pretty localized so I just decided to do them here.

This PR was originally authored by @haewiful

Summary by CodeRabbit

  • New Features
    • Added optional “JSpecify JDK models” support for stronger nullability analysis of JDK APIs.
    • Introduced a new Error Prone flag to enable these models only in JSpecify mode.
  • Documentation
    • Added/expanded instructions to regenerate the bundled JSpecify JDK .astubx artifact.
  • Bug Fixes
    • Improved handling when expected model resources are missing.
  • Tests
    • Added coverage for JSpecify JDK model behavior (enabled vs. disabled) and for correct flag usage.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds the JSpecifyJDKModels configuration flag, validates that it is used only in JSpecify mode, and wires it into the build. ExternalStubxLibraryModels loads the bundled jspecify-jdk.astubx independently from Android JarInfer models. The resource and regeneration workflow are documented, missing stubx resources are rejected explicitly, and tests cover enabled, disabled, and invalid configurations.

Possibly related issues

  • uber/NullAway issue 950 — Directly tracks adding the JSpecifyJDKModels flag and loading generated JSpecify JDK models.

Possibly related PRs

  • uber/NullAway#1432 — Updates the JSpecify JDK annotation serialization pipeline used by the bundled stub artifact.
  • uber/NullAway#1646 — Directly overlaps with JSpecify JDK model flag wiring, loading, and regression tests.
  • uber/NullAway#1456 — Overlaps with the ASTUBX loading and nested annotation handling in ExternalStubxLibraryModels and StubxCacheUtil.

Suggested reviewers: yuxincs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding JSpecify JDK models behind a flag.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jdk-astubx

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@nullaway/src/main/java/com/uber/nullaway/handlers/LibraryModelsHandler.java`:
- Around line 1681-1692: Rename the bundled resource from output.astubx to
nullaway-jspecify-jdk.astubx and update the JDK model loading block guarded by
isJSpecifyJDKEnabled to use
ExternalStubxLibraryModels.class.getResourceAsStream(...) instead of accessing
getClass().getClassLoader(). Update the missing-resource log, parseStubStream
call, and success log to reference the new resource name.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 74e7363e-d06a-4ecd-982c-2359bca75b98

📥 Commits

Reviewing files that changed from the base of the PR and between b67e9d3 and bf7d6f6.

📒 Files selected for processing (9)
  • nullaway/build.gradle
  • nullaway/src/main/java/com/uber/nullaway/Config.java
  • nullaway/src/main/java/com/uber/nullaway/DummyOptionsConfig.java
  • nullaway/src/main/java/com/uber/nullaway/ErrorBuilder.java
  • nullaway/src/main/java/com/uber/nullaway/ErrorProneCLIFlagsConfig.java
  • nullaway/src/main/java/com/uber/nullaway/LibraryModels.java
  • nullaway/src/main/java/com/uber/nullaway/handlers/LibraryModelsHandler.java
  • nullaway/src/main/resources/output.astubx
  • nullaway/src/test/java/com/uber/nullaway/JSpecifyJDKModelsTest.java

@msridhar
msridhar changed the base branch from master to nonnull-param-stream-issue July 21, 2026 01:11
@codecov

codecov Bot commented Jul 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 63.15789% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.16%. Comparing base (72aab40) to head (cb47be6).

Files with missing lines Patch % Lines
...m/uber/nullaway/handlers/LibraryModelsHandler.java 57.14% 11 Missing and 1 partial ⚠️
...ava/com/uber/nullaway/handlers/StubxCacheUtil.java 33.33% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master    #1641      +/-   ##
============================================
- Coverage     88.20%   88.16%   -0.04%     
- Complexity     3060     3065       +5     
============================================
  Files           105      105              
  Lines         10282    10302      +20     
  Branches       2074     2079       +5     
============================================
+ Hits           9069     9083      +14     
- Misses          572      576       +4     
- Partials        641      643       +2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@msridhar
msridhar marked this pull request as ready for review July 21, 2026 22:59
Comment on lines +131 to +133
if (stubxInputStream == null) {
throw new RuntimeException("could not get input stream for " + astubxPath);
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is due to the new JDK models (which model the return of getResourceAsStream as @Nullable)

Matcher matcher = METHOD_SIG_PATTERN.matcher(methodSignature);
if (matcher.find()) {
String methodName = matcher.group(2);
String methodName = castToNonNull(matcher.group(2));

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is due to the new JDK models (which model the return of Matcher.group as @Nullable)

ImmutableMap<MethodRef, ImmutableSetMultimap<Integer, NestedAnnotationInfo>> refs) {
return makeOptimizedLookup(
names, refs.keySet(), ref -> NullabilityUtil.castToNonNull(refs.get(ref)));
return makeOptimizedLookup(names, refs.keySet(), ref -> castToNonNull(refs.get(ref)));

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is due to the new static import

@msridhar

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
nullaway/src/main/java/com/uber/nullaway/handlers/StubxCacheUtil.java (1)

130-139: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Close provider resource streams.

parseStubStream() does not close stubxInputStream; wrap the stream acquisition and parsing in try-with-resources to avoid retaining provider JAR resources.

Proposed fix
-        InputStream stubxInputStream = providerClass.getResourceAsStream(astubxPath);
-        if (stubxInputStream == null) {
-          throw new RuntimeException("could not get input stream for " + astubxPath);
-        }
         String stubxLocation = providerClass + ":" + astubxPath;
-        try {
+        try (InputStream stubxInputStream = providerClass.getResourceAsStream(astubxPath)) {
+          if (stubxInputStream == null) {
+            throw new RuntimeException("could not get input stream for " + astubxPath);
+          }
           parseStubStream(stubxInputStream, stubxLocation);
           LOG(DEBUG, "DEBUG", "loaded stubx file " + stubxLocation);
         } catch (IOException e) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@nullaway/src/main/java/com/uber/nullaway/handlers/StubxCacheUtil.java` around
lines 130 - 139, Update the stubx stream handling around
providerClass.getResourceAsStream and parseStubStream in StubxCacheUtil to use
try-with-resources, ensuring stubxInputStream is closed after parsing while
preserving the existing null check, logging, and RuntimeException handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@nullaway/src/main/java/com/uber/nullaway/handlers/LibraryModelsHandler.java`:
- Around line 1680-1694: Update the missing-resource branch in the JSpecify JDK
model loading block to throw an exception naming JSPECIFY_JDK_ASTUBX_FILENAME
instead of only calling astubxLoadLog. Preserve the existing parsing and
successful-load behavior when the resource is present.
- Around line 1658-1660: Update ExternalStubxLibraryModels so constructing
StubxCacheUtil does not eagerly discover JarInfer providers. Separate provider
discovery from cache construction, and perform the discovery only when
isJarInferEnabled is true, preserving JSpecify-only runs without external
JarInfer models.

In `@nullaway/src/test/java/com/uber/nullaway/JSpecifyJDKModelsTest.java`:
- Around line 14-32: Update modelsDisabledDoesNotLoadAstubxModel to construct
its CompilationTestHelper with JSpecifyJavacConfig.withJSpecifyModeArgs(...),
while omitting JSpecifyJDKModels from the configured models. Preserve the
existing AnnotatedPackages=foo setup and Attributes.get() assertion so the test
specifically exercises the disabled JDK-model path in JSpecify mode.

---

Outside diff comments:
In `@nullaway/src/main/java/com/uber/nullaway/handlers/StubxCacheUtil.java`:
- Around line 130-139: Update the stubx stream handling around
providerClass.getResourceAsStream and parseStubStream in StubxCacheUtil to use
try-with-resources, ensuring stubxInputStream is closed after parsing while
preserving the existing null check, logging, and RuntimeException handling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8f065239-1a9f-42c5-be6c-70b404bc5b19

📥 Commits

Reviewing files that changed from the base of the PR and between 3e084c4 and d4be697.

📒 Files selected for processing (11)
  • jdk-javac-plugin/README.md
  • nullaway/build.gradle
  • nullaway/src/main/java/com/uber/nullaway/Config.java
  • nullaway/src/main/java/com/uber/nullaway/DummyOptionsConfig.java
  • nullaway/src/main/java/com/uber/nullaway/ErrorProneCLIFlagsConfig.java
  • nullaway/src/main/java/com/uber/nullaway/LibraryModels.java
  • nullaway/src/main/java/com/uber/nullaway/handlers/LibraryModelsHandler.java
  • nullaway/src/main/java/com/uber/nullaway/handlers/StubxCacheUtil.java
  • nullaway/src/main/resources/jspecify-jdk.astubx
  • nullaway/src/test/java/com/uber/nullaway/ErrorProneCLIFlagsConfigTest.java
  • nullaway/src/test/java/com/uber/nullaway/JSpecifyJDKModelsTest.java

Comment thread nullaway/src/test/java/com/uber/nullaway/JSpecifyJDKModelsTest.java
Base automatically changed from nonnull-param-stream-issue to master July 24, 2026 02:53

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@jdk-javac-plugin/README.md`:
- Around line 22-37: Update the README code block around the shell commands to
include blank lines before and after the fence, declare the fence language as
bash, and ensure the file ends with exactly one newline.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2ee54848-0cfb-4498-b571-e7004bcbc0e3

📥 Commits

Reviewing files that changed from the base of the PR and between d4be697 and b80333f.

📒 Files selected for processing (11)
  • jdk-javac-plugin/README.md
  • nullaway/build.gradle
  • nullaway/src/main/java/com/uber/nullaway/Config.java
  • nullaway/src/main/java/com/uber/nullaway/DummyOptionsConfig.java
  • nullaway/src/main/java/com/uber/nullaway/ErrorProneCLIFlagsConfig.java
  • nullaway/src/main/java/com/uber/nullaway/LibraryModels.java
  • nullaway/src/main/java/com/uber/nullaway/handlers/LibraryModelsHandler.java
  • nullaway/src/main/java/com/uber/nullaway/handlers/StubxCacheUtil.java
  • nullaway/src/main/resources/jspecify-jdk.astubx
  • nullaway/src/test/java/com/uber/nullaway/ErrorProneCLIFlagsConfigTest.java
  • nullaway/src/test/java/com/uber/nullaway/JSpecifyJDKModelsTest.java

Comment thread jdk-javac-plugin/README.md Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
nullaway/src/main/java/com/uber/nullaway/handlers/LibraryModelsHandler.java (1)

1658-1660: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Do not eagerly discover JarInfer models in JSpecify-only mode.

Constructing StubxCacheUtil invokes loadStubxFiles() from its constructor (Line 97 of nullaway/src/main/java/com/uber/nullaway/handlers/StubxCacheUtil.java). Therefore, isJarInferEnabled=false and isJSpecifyJDKEnabled=true still discovers and parses JarInfer providers, violating the two flags’ independence and potentially failing on unrelated JarInfer resources.

Split cache construction from JarInfer provider discovery, or pass the JarInfer flag into StubxCacheUtil and load providers only when it is enabled.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@nullaway/src/main/java/com/uber/nullaway/handlers/LibraryModelsHandler.java`
around lines 1658 - 1660, Update ExternalStubxLibraryModels so StubxCacheUtil
does not eagerly discover or parse JarInfer providers when isJarInferEnabled is
false, including JSpecify-only mode. Split cache construction from provider
discovery or pass the JarInfer flag into StubxCacheUtil and conditionally load
providers only when enabled, while preserving JSpecify model handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@nullaway/src/main/java/com/uber/nullaway/handlers/LibraryModelsHandler.java`:
- Around line 1658-1660: Update ExternalStubxLibraryModels so StubxCacheUtil
does not eagerly discover or parse JarInfer providers when isJarInferEnabled is
false, including JSpecify-only mode. Split cache construction from provider
discovery or pass the JarInfer flag into StubxCacheUtil and conditionally load
providers only when enabled, while preserving JSpecify model handling.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 756a3459-91ab-4b0c-b4c8-1bed3f780fa6

📥 Commits

Reviewing files that changed from the base of the PR and between b80333f and 2a1b233.

📒 Files selected for processing (2)
  • nullaway/src/main/java/com/uber/nullaway/handlers/LibraryModelsHandler.java
  • nullaway/src/main/java/com/uber/nullaway/handlers/StubxCacheUtil.java

@msridhar
msridhar merged commit b9d7871 into master Jul 24, 2026
12 of 14 checks passed
@msridhar
msridhar deleted the jdk-astubx branch July 24, 2026 04:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants