Skip to content

feat(jspecify): complete the @NullMarked opt-in for test packages - #179

Merged
epugh merged 4 commits into
apache:mainfrom
adityamparikh:chore/jspecify-test-packages-upstream
Aug 18, 2026
Merged

feat(jspecify): complete the @NullMarked opt-in for test packages#179
epugh merged 4 commits into
apache:mainfrom
adityamparikh:chore/jspecify-test-packages-upstream

Conversation

@adityamparikh

Copy link
Copy Markdown
Contributor

Stacked on #133 — please merge that first. Until it lands, the diff below
also shows #133's commits. Once #133 is in, this PR reduces to the six
src/test/.../package-info.java files.

Why

@NullMarked on a package-info.java applies to that package only — Java
packages are not hierarchical for annotation purposes. Combined with
NullAway:OnlyNullMarked=true, an unmarked package is exempt from nullness
checking even though NullAway is configured at error level.

#133 marks every main package plus two test packages (containerization,
observability). This adds the six that are still unmarked, so the opt-in
is uniform across main and test:

  • org.apache.solr.mcp.server (test root)
  • org.apache.solr.mcp.server.collection
  • org.apache.solr.mcp.server.config
  • org.apache.solr.mcp.server.indexing
  • org.apache.solr.mcp.server.schema
  • org.apache.solr.mcp.server.search

That takes the test tree from 2/8 packages marked to 8/8.

Scope

Purely declarative. NullAway remains disabled on compileTestJava (see the
comment #133 adds to build.gradle.kts), so these files change no compilation
outcome today — they make the opt-in complete and consistent, so that enabling
test-side enforcement later is a one-line change rather than a rediscovery of
which packages were missed.

For sizing the follow-up: flipping that one line on this branch surfaces
48 NullAway errors across 14 test files, measured by temporarily replacing
the compileTestJava disable and running ./gradlew compileTestJava --rerun-tasks. The ~30 in #133's new build.gradle.kts comment is an
under-estimate — worth correcting there, but left alone here so this PR stays
additive-only.

Each site is a test unboxing or dereferencing a value that production code
declares @Nullable (metrics fields that are null when a Solr endpoint is
unavailable). They're mechanical to fix — extract a local, assertNotNull
but 48 of them is its own PR, not a rider on this one.

Testing

./gradlew build passes on this branch (JDK 25, Testcontainers) — full suite
green, spotlessApply reports no reformatting.

@adityamparikh adityamparikh changed the title chore(jspecify): complete the @NullMarked opt-in for test packages feat(jspecify): complete the @NullMarked opt-in for test packages Aug 2, 2026
adityamparikh and others added 3 commits August 18, 2026 17:19
Background: prior to this change only the root package
`org.apache.solr.mcp.server` was @NullMarked via package-info.java. All
sub-packages — `.collection`, `.config`, `.indexing`,
`.indexing.documentcreator`, `.metadata`, `.search`, `.security`,
`.util`, plus the test-only `.containerization` and `.observability` —
were running unannotated, so NullAway (`OnlyNullMarked=true`) was
silently skipping them.

Changes:

1. Adds `package-info.java` with `@NullMarked` to every sub-package (10
   files: 8 main + 2 test-only).

2. Annotates production code with `@Nullable` where return types,
   parameters, or record components legitimately admit null. The
   non-obvious nullable surfaces:
   - `CollectionUtils.getLong/getFloat/getInteger` return null on missing
     or unparseable keys.
   - `CollectionService` cache/handler metrics methods return null when
     the underlying Solr endpoint is unavailable (graceful degradation
     by design).
   - `SolrMetrics.cacheStats` / `handlerStats`, `CacheStats.*`,
     `CacheInfo.*`, `HandlerStats.*`, `HandlerInfo.*`,
     `SolrHealthStatus.errorMessage` / `responseTime` / `totalDocuments`
     / `solrVersion` / `status` — all documented as nullable, now
     annotated.
   - `IndexStats.numDocs` / `segmentCount` — Luke can return either
     field as null.
   - Optional `@McpToolParam(required = false)` parameters on
     `CollectionService.createCollection` and `SearchService.search`.
   - `JsonResponseParser.convertValue` — JSON null inputs.

3. `HttpSecurityConfiguration` Spring `@Value` fields initialised with
   defaults (`""` for `issuerUrl` matching the property default,
   `List.of()` for `allowedOrigins`) so the analyser can see they are
   always non-null after construction.

4. NullAway is explicitly disabled on `compileTestJava` (with an
   explanatory comment). The @NullMarked rollout exposes ~30 test sites
   that unbox or dereference values now declared @nullable in
   production (Map.get returns, metric fields that are null when an
   endpoint is unavailable, etc.). Each can be tightened by extracting
   to a local + `assertNotNull`, but the volume makes it a deliberate
   follow-up. Production is fully enforced.

Build verified green (compile + unit + integration).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: adityamparikh <aditya.m.parikh@gmail.com>
The method unconditionally returns `new CacheStats(...)`; null-wrapping
happens one level up in `fetchCacheMetrics` via the `isCacheStatsEmpty`
check. The @nullable was misleading — readers expect a method marked
@nullable to actually have a `return null` path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: adityamparikh <aditya.m.parikh@gmail.com>
@NullMarked on a package-info.java applies to that package only - Java
packages are not hierarchical for annotation purposes. Combined with
NullAway:OnlyNullMarked=true, that means an unmarked package is exempt from
nullness checking even though NullAway is configured at error level.

apache#133 marked every main package and two test packages (containerization,
observability). This adds the six that were still unmarked, so every main
and test package is now null-marked and the opt-in is uniform.

NullAway remains disabled on compileTestJava, so this is declarative for
now. Enabling it surfaces 48 test sites (the note in build.gradle.kts
estimates ~30); that is left as a follow-up rather than folded in here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Aditya Parikh <aditya.m.parikh@gmail.com>
@adityamparikh
adityamparikh force-pushed the chore/jspecify-test-packages-upstream branch from a3104c6 to b74f25b Compare August 18, 2026 21:23
@epugh
epugh merged commit a84033b into apache:main Aug 18, 2026
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.

2 participants