Skip to content

Conversation

@msridhar
Copy link
Collaborator

@msridhar msridhar commented Aug 14, 2025

As of JDK 21.0.8, the patch to properly expose type use annotations via standard APIs has landed, guarded behind the flag -XDaddTypeAnnotationsToSymbol=true. This PR runs the relevant tests on JDK 21 by passing that flag where needed. This means NullAway regression tests will fail on versions of JDK 21 older than 21.0.8, but we can document that.

Summary by CodeRabbit

  • Tests

    • Expanded coverage by enabling previously excluded generics-related tests.
    • Added runtime guards for JDK 21+ to ensure reliable execution.
    • Standardized test configuration for consistent compiler settings.
  • Chores

    • Simplified Gradle test filtering to run tests consistently across Java versions.
  • Notes

    • No changes to public API or user-facing behavior.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 14, 2025

Walkthrough

Updates test configurations and guards across multiple test suites to use List.of, add -XDaddTypeAnnotationsToSymbol=true, and gate certain tests on JDK feature >= 21. Removes a Gradle test-exclusion block so previously excluded jspecify tests now run. No public API changes.

Changes

Cohort / File(s) Summary of Changes
JSpecify/Guava test runtime guards and args
guava-recent-unit-tests/src/test/java/com/uber/nullaway/guava/NullAwayGuavaParametricNullnessTests.java, nullaway/src/test/java/com/uber/nullaway/jspecify/BytecodeGenericsTests.java
Switched Arrays.asList(...) to List.of(...); added compiler arg -XDaddTypeAnnotationsToSymbol=true; added Assume-based runtime guards requiring Runtime.version().feature() >= 21; adjusted guards in Guava tests from >= 23 to >= 21; replaced @ignore with Assume skip.
Test helper base args
nullaway/src/test/java/com/uber/nullaway/NullAwayTestsBase.java
Replaced Arrays.asList(...) with List.of(...); added -XDaddTypeAnnotationsToSymbol=true to javac args.
Gradle test filtering
nullaway/build.gradle
Removed pre-JDK-22 test exclusion; BytecodeGenericsTests generics checks now always included regardless of test.javaVersion.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch run-jspecify-bytecode-tests-on-jdk-21.0.8

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

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

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@msridhar msridhar requested a review from yuxincs August 14, 2025 18:07
@codecov
Copy link

codecov bot commented Aug 14, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 88.50%. Comparing base (f59d952) to head (433f70c).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff            @@
##             master    #1245   +/-   ##
=========================================
  Coverage     88.50%   88.50%           
  Complexity     2373     2373           
=========================================
  Files            90       90           
  Lines          7802     7802           
  Branches       1555     1555           
=========================================
  Hits           6905     6905           
  Misses          452      452           
  Partials        445      445           

☔ View full report in Codecov by Sentry.
📢 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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🧹 Nitpick comments (4)
nullaway/src/main/java/com/uber/nullaway/NullabilityUtil.java (1)

666-670: Good utility; minor doc clarification to avoid confusion on 22+.

The helper is correct for gating the -XD flag on 21u8+. Consider clarifying in the Javadoc that this returns false for JDK 22+ intentionally, since the flag is not required there.

nullaway/src/test/java/com/uber/nullaway/jspecify/BytecodeGenericsTests.java (1)

233-236: Optional: centralize the repeated assumption into a helper.

To avoid drift across tests and improve readability, you could add a single helper method and use it at all the guarded sites.

Add this method inside the class:

private static boolean jdkReadsTypeUseAnnotationsFromBytecode() {
  int feature = Runtime.version().feature();
  return feature > 21 || NullabilityUtil.isJDK21Update8OrHigher();
}

Then replace each occurrence with:

Assume.assumeTrue(jdkReadsTypeUseAnnotationsFromBytecode());

Also applies to: 80-82, 105-107, 251-259

guava-recent-unit-tests/src/test/java/com/uber/nullaway/guava/NullAwayGuavaParametricNullnessTests.java (2)

59-71: Optional: centralize the guard to avoid duplication.

Add a private helper in this test class and call it in all guarded tests to ensure future updates remain consistent.

Add:

private static boolean jdkReadsTypeUseAnnotationsFromBytecode() {
  int feature = Runtime.version().feature();
  return feature > 21 || NullabilityUtil.isJDK21Update8OrHigher();
}

Then replace the Assume lines with:

Assume.assumeTrue(jdkReadsTypeUseAnnotationsFromBytecode());

Also applies to: 101-102, 149-150, 179-180, 261-262


59-71: Document the 21.0.8+ requirement in test comments.

A brief comment noting “requires JDK 21.0.8+ (or 22+) to read type-use annotations from bytecode” will save future readers from rediscovering the guard rationale.

Also applies to: 98-123, 146-174, 176-197, 259-275

📜 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 settings in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ba4ff83 and ab93566.

📒 Files selected for processing (4)
  • guava-recent-unit-tests/src/test/java/com/uber/nullaway/guava/NullAwayGuavaParametricNullnessTests.java (6 hunks)
  • nullaway/build.gradle (0 hunks)
  • nullaway/src/main/java/com/uber/nullaway/NullabilityUtil.java (1 hunks)
  • nullaway/src/test/java/com/uber/nullaway/jspecify/BytecodeGenericsTests.java (5 hunks)
💤 Files with no reviewable changes (1)
  • nullaway/build.gradle
🧰 Additional context used
🧬 Code Graph Analysis (1)
nullaway/src/test/java/com/uber/nullaway/jspecify/BytecodeGenericsTests.java (2)
nullaway/src/test/java/com/uber/nullaway/NullAwayTestsBase.java (1)
  • NullAwayTestsBase (10-51)
nullaway/src/main/java/com/uber/nullaway/NullabilityUtil.java (1)
  • NullabilityUtil (66-671)
🔇 Additional comments (2)
nullaway/src/test/java/com/uber/nullaway/jspecify/BytecodeGenericsTests.java (1)

251-259: Args builder and conditional -XD flag look good.

Using ImmutableList.Builder enables clean conditional injection of -XDaddTypeAnnotationsToSymbol for 21u8+. This aligns with the JDK behavior described in the PR.

guava-recent-unit-tests/src/test/java/com/uber/nullaway/guava/NullAwayGuavaParametricNullnessTests.java (1)

59-71: Args builder + conditional -XD flag is correct and future-proof.

This mirrors the JDK 21u8+ behavior and keeps 22+ untouched. Nice cleanup from Arrays.asList to builder for conditional logic.

@msridhar msridhar enabled auto-merge (squash) August 14, 2025 18:53
@msridhar msridhar disabled auto-merge August 14, 2025 21:50
@msridhar msridhar enabled auto-merge (squash) August 14, 2025 22:40
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (3)
nullaway/src/test/java/com/uber/nullaway/jspecify/BytecodeGenericsTests.java (3)

79-80: Tighten JDK guard: require 21u8+ (with -XD) or 22+

feature() >= 21 will run on 21.0.0–21.0.7 where bytecode type-use annotations are not exposed; these tests will flake/fail there. Use the existing utility so the test only runs when supported.

-    // to read annotations properly from bytecode
-    Assume.assumeTrue(Runtime.version().feature() >= 21);
+    // Only run where bytecode type-use annotations are available:
+    // JDK 21.0.8+ (with -XDaddTypeAnnotationsToSymbol=true) or JDK 22+
+    Assume.assumeTrue(
+        com.uber.nullaway.util.NullabilityUtil.isJDK21Update8OrHigher()
+            || Runtime.version().feature() > 21);

104-105: Same guard tightening needed here

Align with the stricter check to avoid executing on 21.0.0–21.0.7.

-    // to read annotations properly from bytecode
-    Assume.assumeTrue(Runtime.version().feature() >= 21);
+    // Only run where bytecode type-use annotations are available:
+    // JDK 21.0.8+ (with -XDaddTypeAnnotationsToSymbol=true) or JDK 22+
+    Assume.assumeTrue(
+        com.uber.nullaway.util.NullabilityUtil.isJDK21Update8OrHigher()
+            || Runtime.version().feature() > 21);

233-234: Same guard tightening needed here

Ensure this also only runs on 21u8+ or 22+.

-    // to read annotations properly from bytecode
-    Assume.assumeTrue(Runtime.version().feature() >= 21);
+    // Only run where bytecode type-use annotations are available:
+    // JDK 21.0.8+ (with -XDaddTypeAnnotationsToSymbol=true) or JDK 22+
+    Assume.assumeTrue(
+        com.uber.nullaway.util.NullabilityUtil.isJDK21Update8OrHigher()
+            || Runtime.version().feature() > 21);
🧹 Nitpick comments (1)
nullaway/src/test/java/com/uber/nullaway/NullAwayTestsBase.java (1)

19-36: Gate -XDaddTypeAnnotationsToSymbol to JDK 21u8+ (or verify it’s harmless on older JDKs)

You’re now passing the internal -XDaddTypeAnnotationsToSymbol=true flag via the default helper for all tests. While -XD generally accepts unknown keys, relying on that across older JDKs (e.g., 17) is brittle. Either:

  • Gate the flag to only JDK 21 update 8+ (where it matters), or
  • Confirm it’s a no-op on all JDKs in CI and keep as-is.

If you prefer gating, here’s a concrete refactor to keep args immutable at the call-site while conditionally adding the flag:

-        makeTestHelperWithArgs(
-            List.of(
+        makeTestHelperWithArgs(
+            buildDefaultArgs(
                 "-d",
                 temporaryFolder.getRoot().getAbsolutePath(),
                 "-XepOpt:NullAway:KnownInitializers="
                     + "com.uber.nullaway.testdata.CheckFieldInitNegativeCases.Super.doInit,"
                     + "com.uber.nullaway.testdata.CheckFieldInitNegativeCases"
                     + ".SuperInterface.doInit2",
                 "-XepOpt:NullAway:AnnotatedPackages=com.uber,com.ubercab,io.reactivex",
                 // We give the following in Regexp format to test that support
                 "-XepOpt:NullAway:UnannotatedSubPackages=com.uber.nullaway.[a-zA-Z0-9.]+.unannotated",
                 "-XepOpt:NullAway:ExcludedClasses="
                     + "com.uber.nullaway.testdata.Shape_Stuff,"
                     + "com.uber.nullaway.testdata.excluded",
                 "-XepOpt:NullAway:ExcludedClassAnnotations=com.uber.nullaway.testdata.TestAnnot",
                 "-XepOpt:NullAway:CastToNonNullMethod=com.uber.nullaway.testdata.Util.castToNonNull",
                 "-XepOpt:NullAway:ExternalInitAnnotations=com.uber.ExternalInit",
                 "-XepOpt:NullAway:ExcludedFieldAnnotations=com.uber.ExternalFieldInit",
-                "-XDaddTypeAnnotationsToSymbol=true"));
+                "-XDaddTypeAnnotationsToSymbol=true"));

And add this helper in the same class (outside the selected range), to keep setup() clean and preserve immutability for callers:

// Add near other helpers:
private static List<String> buildDefaultArgs(String... baseArgs) {
  // Base immutable list
  List<String> args = List.of(baseArgs);
  // Only keep the -XD flag when it is relevant and safe (21u8+); skip on others.
  if (com.uber.nullaway.util.NullabilityUtil.isJDK21Update8OrHigher()) {
    return args;
  }
  // Remove the -XD flag if present (older JDKs or 22+ where it’s unnecessary)
  return args.stream()
      .filter(a -> !a.equals("-XDaddTypeAnnotationsToSymbol=true"))
      .toList();
}

This ensures:

  • Tests don’t rely on undocumented behavior of unknown -XD keys on older JDKs.
  • The flag remains present for JDK 21u8+ where the JSpecify bytecode reading fix exists and is gated by the flag.

Would you like me to push a follow-up commit that adds this helper and updates callers?

📜 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.

📥 Commits

Reviewing files that changed from the base of the PR and between ab93566 and 9b9e1f0.

📒 Files selected for processing (3)
  • guava-recent-unit-tests/src/test/java/com/uber/nullaway/guava/NullAwayGuavaParametricNullnessTests.java (6 hunks)
  • nullaway/src/test/java/com/uber/nullaway/NullAwayTestsBase.java (2 hunks)
  • nullaway/src/test/java/com/uber/nullaway/jspecify/BytecodeGenericsTests.java (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • guava-recent-unit-tests/src/test/java/com/uber/nullaway/guava/NullAwayGuavaParametricNullnessTests.java
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: msridhar
PR: uber/NullAway#1245
File: guava-recent-unit-tests/src/test/java/com/uber/nullaway/guava/NullAwayGuavaParametricNullnessTests.java:101-102
Timestamp: 2025-08-14T18:50:06.094Z
Learning: In NullAway JSpecify tests, when JDK version requirements exist due to bytecode annotation reading capabilities, prefer failing tests over skipping them on unsupported versions to ensure CI catches regressions and enforces proper JDK version usage for developers.
📚 Learning: 2025-08-14T18:50:06.094Z
Learnt from: msridhar
PR: uber/NullAway#1245
File: guava-recent-unit-tests/src/test/java/com/uber/nullaway/guava/NullAwayGuavaParametricNullnessTests.java:101-102
Timestamp: 2025-08-14T18:50:06.094Z
Learning: In NullAway JSpecify tests, when JDK version requirements exist due to bytecode annotation reading capabilities, prefer failing tests over skipping them on unsupported versions to ensure CI catches regressions and enforces proper JDK version usage for developers.

Applied to files:

  • nullaway/src/test/java/com/uber/nullaway/NullAwayTestsBase.java
  • nullaway/src/test/java/com/uber/nullaway/jspecify/BytecodeGenericsTests.java
🔇 Additional comments (2)
nullaway/src/test/java/com/uber/nullaway/jspecify/BytecodeGenericsTests.java (2)

5-6: LGTM on imports.

Switching to List and adding Assume imports is correct given the new usage.


251-254: LGTM: include -XDaddTypeAnnotationsToSymbol for jspecify tests

Setting the flag here is correct since setArgs replaces the default args and these tests rely on reading type-use annotations from bytecode. List.of(...) usage also looks good.

@msridhar msridhar merged commit bdca1c3 into master Aug 17, 2025
13 checks passed
@msridhar msridhar deleted the run-jspecify-bytecode-tests-on-jdk-21.0.8 branch August 17, 2025 15:18
@sdeleuze
Copy link

@msridhar Does that mean -XDaddTypeAnnotationsToSymbol=true with JDK 21.0.8+ and JDK 24 should now be equivalent from NullAway checks POV, or do you still have tests passing with JDK 24 but not JDK 21.0.8+?

@msridhar
Copy link
Collaborator Author

@sdeleuze there is one test involving a downcast and an intersection type that only passes on JDK 23+ (see #1022). Beyond that one, all tests that pass on JDK 24 also pass on JDK 21.0.8+ with the extra flag. It's not high priority but if it became important we could probably fix #1022 on earlier JDKs as well.

@sdeleuze
Copy link

Good to know that we are pretty close. Let see how the potential Java 17 backport goes, that may increase the priority but we are not there yet.

msridhar added a commit that referenced this pull request Aug 27, 2025
Some JSpecify tests now fail on earlier JDK 21 builds (see #1245). To
avoid confusion, fail the whole build if one of these versions is being
used.
This was referenced Sep 1, 2025
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.

4 participants