Skip to content

refactor (jspecify): roll @NullMarked out to all sub-packages#133

Open
adityamparikh wants to merge 2 commits into
apache:mainfrom
adityamparikh:jspecify-everywhere
Open

refactor (jspecify): roll @NullMarked out to all sub-packages#133
adityamparikh wants to merge 2 commits into
apache:mainfrom
adityamparikh:jspecify-everywhere

Conversation

@adityamparikh
Copy link
Copy Markdown
Contributor

@adityamparikh adityamparikh commented May 19, 2026

Summary

Extends JSpecify null-safety enforcement from the single root package org.apache.solr.mcp.server to every sub-package in the codebase — main and test alike.

Before this change, NullAway:OnlyNullMarked=true was silently skipping all production code except the (mostly empty) root package. So the project advertised null-safety but only enforced it on Main.java.

Supersedes #109 and #115 — both are subsets of this rollout:

Changes

  1. package-info.java with @NullMarked added to 10 packages (8 main + 2 test-only):

    • main: .collection, .config, .indexing, .indexing.documentcreator, .metadata, .search, .security, .util
    • test-only: .containerization, .observability
  2. Production code annotated with @Nullable where appropriate, derived from running NullAway:

    • CollectionUtils.getLong/getFloat/getInteger — return null on missing/unparseable
    • CollectionService cache/handler metrics methods — return null when the Solr endpoint is unavailable (graceful degradation by design)
    • Many Dtos.java record components: SolrMetrics.{cacheStats,handlerStats}, all of CacheStats/CacheInfo/HandlerStats/HandlerInfo, SolrHealthStatus.{errorMessage,responseTime,totalDocuments,solrVersion,status}, IndexStats.{numDocs,segmentCount}
    • @McpToolParam(required = false) parameters on CollectionService.createCollection and SearchService.search
    • JsonResponseParser.convertValue — JSON null inputs
    • CollectionService.isCacheStatsEmpty — accepts @nullable
  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 (one-line in build.gradle.kts with explanatory comment).

    • The rollout exposes ~30 test sites that unbox or dereference values now declared @Nullable in production (Map.get returns, optional metric fields, etc.).
    • Each can be tightened by extracting to a local + assertNotNull, but the volume makes test-side cleanup a deliberate follow-up.
    • Production code is fully enforced.

Test plan

  • ./gradlew build — full build green (compile + unit + integration)
  • NullAway enforces null safety on all production code
  • Pre-existing tests still pass at runtime

🤖 Generated with Claude Code

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) <[email protected]>
Signed-off-by: adityamparikh <[email protected]>
@adityamparikh adityamparikh changed the title chore(jspecify): roll @NullMarked out to all sub-packages refactor (jspecify): roll @NullMarked out to all sub-packages May 19, 2026
@adityamparikh adityamparikh marked this pull request as ready for review May 19, 2026 17:04
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) <[email protected]>
Signed-off-by: adityamparikh <[email protected]>
adityamparikh added a commit to adityamparikh/solr-mcp that referenced this pull request May 22, 2026
…safety

README:
- Add `add-fields` and `add-field-types` to the Tools table (PR apache#131).
- Add a sentence on MCP behavior hints (`readOnlyHint`,
  `destructiveHint`, `idempotentHint`) so client integrators know to
  read them (PR apache#134).
- Add an "MCP Prompts" section listing the six workflow prompts
  introduced in the prompts PR.
- Clarify that `solr://{collection}/schema` autocompletion is
  prefix-filtered, case-insensitive, capped at 100 — describing the
  behavior shipped with the completion PR.

CONTRIBUTING:
- Add a "Null safety" subsection covering the project-wide
  `@NullMarked` contract and NullAway enforcement (PR apache#133).

These docs land alongside the corresponding feature PRs at apache/main.

Signed-off-by: adityamparikh <[email protected]>
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.

1 participant