From 7a3d03f416bae57051369873344ca8b417b4f194 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 28 Feb 2026 23:21:37 +0000 Subject: [PATCH 01/71] Add JSpecify agent team orchestrator prompt https://claude.ai/code/session_01FG3V2VvjSSbUVcjn9FX4yx --- jspecify-team-prompt.md | 394 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 394 insertions(+) create mode 100644 jspecify-team-prompt.md diff --git a/jspecify-team-prompt.md b/jspecify-team-prompt.md new file mode 100644 index 000000000..fb5d3e28f --- /dev/null +++ b/jspecify-team-prompt.md @@ -0,0 +1,394 @@ +# JSpecify Annotation Team Orchestrator Prompt + +You are an orchestrator agent responsible for coordinating a team of worker +agents to add JSpecify nullability annotations to public API classes in the +graphql-java project. + +## Your Job + +1. Read the current exemption list from: + `src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy` + Before building batch assignments, check which classes from the lists below + are still present in the exemption list. Only assign classes that remain. + This makes the orchestrator safe to re-run after interruption. + +2. Group the remaining classes into batches (see batches below). + +3. Launch worker agents in **waves of 3** to manage token usage. + After each wave completes, launch the reviewer before starting the next wave. + Only proceed to the next wave if the reviewer reports no NullAway errors. + +4. After all waves are complete, launch the validator. + +## Execution Flow + +### Wave 1 +Launch Workers 1, 2, 3 in parallel. Wait for all to complete. +Launch Reviewer for Wave 1. Wait for completion and NullAway confirmation. + +### Wave 2 +Launch Workers 5, 6, 7 in parallel. Wait for all to complete. +Launch Reviewer for Wave 2. Wait for completion and NullAway confirmation. + +### Wave 3 +Launch Workers 8, 9 in parallel. Wait for all to complete. +Launch Reviewer for Wave 3. Wait for completion and NullAway confirmation. + +### Final Step +Launch the validator to remove completed classes from +`JSpecifyAnnotationsCheck.groovy` and push the branch. + +--- + +## Batch Assignments + +### Worker 1 — graphql.analysis (16 classes) +``` +graphql.analysis.QueryComplexityCalculator +graphql.analysis.QueryComplexityInfo +graphql.analysis.QueryDepthInfo +graphql.analysis.QueryReducer +graphql.analysis.QueryTransformer +graphql.analysis.QueryTraversalOptions +graphql.analysis.QueryVisitor +graphql.analysis.QueryVisitorFieldArgumentEnvironment +graphql.analysis.QueryVisitorFieldArgumentInputValue +graphql.analysis.QueryVisitorFieldArgumentValueEnvironment +graphql.analysis.QueryVisitorFieldEnvironment +graphql.analysis.QueryVisitorFragmentDefinitionEnvironment +graphql.analysis.QueryVisitorFragmentSpreadEnvironment +graphql.analysis.QueryVisitorInlineFragmentEnvironment +graphql.analysis.QueryVisitorStub +graphql.analysis.values.ValueTraverser +``` + +### Worker 2 — graphql.execution core (26 classes) +``` +graphql.execution.AbortExecutionException +graphql.execution.AsyncExecutionStrategy +graphql.execution.AsyncSerialExecutionStrategy +graphql.execution.CoercedVariables +graphql.execution.DataFetcherExceptionHandlerParameters +graphql.execution.DataFetcherExceptionHandlerResult +graphql.execution.DefaultValueUnboxer +graphql.execution.ExecutionContext +graphql.execution.ExecutionId +graphql.execution.ExecutionStepInfo +graphql.execution.ExecutionStrategyParameters +graphql.execution.FetchedValue +graphql.execution.FieldValueInfo +graphql.execution.InputMapDefinesTooManyFieldsException +graphql.execution.MergedSelectionSet +graphql.execution.MissingRootTypeException +graphql.execution.NonNullableValueCoercedAsNullException +graphql.execution.NormalizedVariables +graphql.execution.OneOfNullValueException +graphql.execution.OneOfTooManyKeysException +graphql.execution.ResultNodesInfo +graphql.execution.ResultPath +graphql.execution.SimpleDataFetcherExceptionHandler +graphql.execution.SubscriptionExecutionStrategy +graphql.execution.UnknownOperationException +graphql.execution.UnresolvedTypeException +``` + +### Worker 3 — graphql.execution sub-packages (24 classes) +``` +graphql.execution.conditional.ConditionalNodeDecision +graphql.execution.directives.QueryAppliedDirective +graphql.execution.directives.QueryAppliedDirectiveArgument +graphql.execution.directives.QueryDirectives +graphql.execution.instrumentation.fieldvalidation.FieldValidationInstrumentation +graphql.execution.instrumentation.fieldvalidation.SimpleFieldValidation +graphql.execution.instrumentation.parameters.InstrumentationCreateStateParameters +graphql.execution.instrumentation.parameters.InstrumentationExecuteOperationParameters +graphql.execution.instrumentation.parameters.InstrumentationExecutionParameters +graphql.execution.instrumentation.parameters.InstrumentationExecutionStrategyParameters +graphql.execution.instrumentation.parameters.InstrumentationFieldCompleteParameters +graphql.execution.instrumentation.parameters.InstrumentationFieldFetchParameters +graphql.execution.instrumentation.parameters.InstrumentationFieldParameters +graphql.execution.instrumentation.parameters.InstrumentationValidationParameters +graphql.execution.instrumentation.tracing.TracingInstrumentation +graphql.execution.instrumentation.tracing.TracingSupport +graphql.execution.preparsed.PreparsedDocumentEntry +graphql.execution.preparsed.persisted.ApolloPersistedQuerySupport +graphql.execution.preparsed.persisted.InMemoryPersistedQueryCache +graphql.execution.preparsed.persisted.PersistedQueryCacheMiss +graphql.execution.preparsed.persisted.PersistedQueryIdInvalid +graphql.execution.preparsed.persisted.PersistedQueryNotFound +graphql.execution.reactive.DelegatingSubscription +graphql.execution.reactive.SubscriptionPublisher +``` + +### Worker 5 — graphql.language (remaining) + graphql.normalized (23 classes) +``` +graphql.language.ScalarTypeDefinition +graphql.language.ScalarTypeExtensionDefinition +graphql.language.SchemaDefinition +graphql.language.SchemaExtensionDefinition +graphql.language.Selection +graphql.language.SelectionSet +graphql.language.SelectionSetContainer +graphql.language.TypeKind +graphql.language.TypeName +graphql.language.UnionTypeDefinition +graphql.language.UnionTypeExtensionDefinition +graphql.language.VariableDefinition +graphql.normalized.ExecutableNormalizedField +graphql.normalized.ExecutableNormalizedOperation +graphql.normalized.ExecutableNormalizedOperationFactory +graphql.normalized.ExecutableNormalizedOperationToAstCompiler +graphql.normalized.NormalizedInputValue +graphql.normalized.incremental.NormalizedDeferredExecution +graphql.normalized.nf.NormalizedDocument +graphql.normalized.nf.NormalizedDocumentFactory +graphql.normalized.nf.NormalizedField +graphql.normalized.nf.NormalizedOperation +graphql.normalized.nf.NormalizedOperationToAstCompiler +``` + +### Worker 6 — graphql.schema core types (38 classes) +``` +graphql.schema.AsyncDataFetcher +graphql.schema.CoercingParseLiteralException +graphql.schema.CoercingParseValueException +graphql.schema.CoercingSerializeException +graphql.schema.DataFetcherFactories +graphql.schema.DataFetcherFactoryEnvironment +graphql.schema.DataFetchingFieldSelectionSet +graphql.schema.DefaultGraphqlTypeComparatorRegistry +graphql.schema.DelegatingDataFetchingEnvironment +graphql.schema.FieldCoordinates +graphql.schema.GraphQLAppliedDirectiveArgument +graphql.schema.GraphQLArgument +graphql.schema.GraphQLCompositeType +graphql.schema.GraphQLDirective +graphql.schema.GraphQLDirectiveContainer +graphql.schema.GraphQLEnumValueDefinition +graphql.schema.GraphQLFieldDefinition +graphql.schema.GraphQLFieldsContainer +graphql.schema.GraphQLImplementingType +graphql.schema.GraphQLInputFieldsContainer +graphql.schema.GraphQLInputObjectField +graphql.schema.GraphQLInputObjectType +graphql.schema.GraphQLInputSchemaElement +graphql.schema.GraphQLInputType +graphql.schema.GraphQLInputValueDefinition +graphql.schema.GraphQLInterfaceType +graphql.schema.GraphQLModifiedType +graphql.schema.GraphQLNamedOutputType +graphql.schema.GraphQLNamedSchemaElement +graphql.schema.GraphQLNamedType +graphql.schema.GraphQLNonNull +graphql.schema.GraphQLNullableType +graphql.schema.GraphQLObjectType +graphql.schema.GraphQLOutputType +graphql.schema.GraphQLSchemaElement +graphql.schema.GraphQLTypeReference +graphql.schema.GraphQLTypeVisitor +graphql.schema.GraphQLTypeVisitorStub +graphql.schema.GraphQLUnmodifiedType +``` + +### Worker 7 — graphql.schema utilities + sub-packages (41 classes) +``` +graphql.schema.GraphqlElementParentTree +graphql.schema.GraphqlTypeComparatorEnvironment +graphql.schema.GraphqlTypeComparatorRegistry +graphql.schema.InputValueWithState +graphql.schema.SchemaElementChildrenContainer +graphql.schema.SchemaTransformer +graphql.schema.SchemaTraverser +graphql.schema.SelectedField +graphql.schema.StaticDataFetcher +graphql.schema.diff.DiffCategory +graphql.schema.diff.DiffEvent +graphql.schema.diff.DiffLevel +graphql.schema.diff.DiffSet +graphql.schema.diff.SchemaDiffSet +graphql.schema.diff.reporting.CapturingReporter +graphql.schema.diff.reporting.ChainedReporter +graphql.schema.diff.reporting.PrintStreamReporter +graphql.schema.idl.CombinedWiringFactory +graphql.schema.idl.MapEnumValuesProvider +graphql.schema.idl.NaturalEnumValuesProvider +graphql.schema.idl.RuntimeWiring +graphql.schema.idl.SchemaDirectiveWiring +graphql.schema.idl.SchemaDirectiveWiringEnvironment +graphql.schema.idl.SchemaGenerator +graphql.schema.idl.SchemaPrinter +graphql.schema.idl.TypeRuntimeWiring +graphql.schema.idl.errors.SchemaProblem +graphql.schema.idl.errors.StrictModeWiringException +graphql.schema.transform.FieldVisibilitySchemaTransformation +graphql.schema.transform.VisibleFieldPredicateEnvironment +graphql.schema.usage.SchemaUsage +graphql.schema.usage.SchemaUsageSupport +graphql.schema.validation.OneOfInputObjectRules +graphql.schema.validation.SchemaValidationErrorClassification +graphql.schema.visibility.BlockedFields +graphql.schema.visibility.DefaultGraphqlFieldVisibility +graphql.schema.visibility.GraphqlFieldVisibility +graphql.schema.visibility.NoIntrospectionGraphqlFieldVisibility +graphql.schema.visitor.GraphQLSchemaTraversalControl +``` + +### Worker 8 — graphql.extensions + graphql.incremental + graphql.introspection (15 classes) +``` +graphql.extensions.ExtensionsBuilder +graphql.incremental.DeferPayload +graphql.incremental.DelayedIncrementalPartialResult +graphql.incremental.DelayedIncrementalPartialResultImpl +graphql.incremental.IncrementalExecutionResult +graphql.incremental.IncrementalExecutionResultImpl +graphql.incremental.IncrementalPayload +graphql.incremental.StreamPayload +graphql.introspection.GoodFaithIntrospection +graphql.introspection.Introspection +graphql.introspection.IntrospectionQuery +graphql.introspection.IntrospectionQueryBuilder +graphql.introspection.IntrospectionResultToSchema +graphql.introspection.IntrospectionWithDirectivesSupport +graphql.introspection.IntrospectionWithDirectivesSupport$DirectivePredicateEnvironment +``` + +### Worker 9 — graphql.parser + graphql.util (18 classes) +``` +graphql.parser.InvalidSyntaxException +graphql.parser.MultiSourceReader +graphql.parser.Parser +graphql.parser.ParserEnvironment +graphql.parser.ParserOptions +graphql.util.CyclicSchemaAnalyzer +graphql.util.NodeAdapter +graphql.util.NodeLocation +graphql.util.NodeMultiZipper +graphql.util.NodeZipper +graphql.util.querygenerator.QueryGenerator +graphql.util.querygenerator.QueryGeneratorOptions +graphql.util.querygenerator.QueryGeneratorOptions$QueryGeneratorOptionsBuilder +graphql.util.querygenerator.QueryGeneratorResult +graphql.util.TraversalControl +graphql.util.TraverserContext +graphql.util.TreeTransformer +graphql.util.TreeTransformerUtil +``` + +--- + +## Instructions for Each Worker Agent + +Each worker agent must follow these rules for every class in its batch: + +### Per-class steps +1. Find the class at `src/main/java/.java` +2. Add `@NullMarked` at the class level +3. Remove redundant `@NonNull` annotations added by IntelliJ +4. Check Javadoc `@param` tags mentioning "null", "nullable", "may be null" +5. Check Javadoc `@return` tags mentioning "null", "optional", "if available" +6. Check method bodies that return null or check for null +7. Consult the GraphQL spec (https://spec.graphql.org/draft/) for the + relevant concept — prioritize spec nullability over IntelliJ inference +8. If the class has a static Builder inner class, annotate it `@NullUnmarked` + and skip further annotation of that inner class +9. Delete unused imports from the class after editing +10. Do NOT modify `JSpecifyAnnotationsCheck.groovy` + +### Generics rules +- `` does NOT allow `@Nullable` type arguments (`Box<@Nullable String>` illegal) +- `` DOES allow `@Nullable` type arguments +- Use `` only when callers genuinely need nullable types + +### After each class +- Commit with message: `"Add JSpecify annotations to ClassName"` +- `git pull` before starting the next class to pick up any concurrent changes + +### If a class has NullAway errors +- Make the smallest possible fix +- Use `Objects.requireNonNull(x, "message")` or `assertNotNull(x, "message")` + only as a last resort +- Do NOT run the full build — leave that for the reviewer + +--- + +## Reviewer Agent Instructions + +After each wave of workers completes, launch a single reviewer agent. +The reviewer must NOT read any worker agent output or context — it works +only from the git diff. + +### Step 1 — Get the diffs + +For each class annotated in this wave, get its diff: +``` +git diff origin/main...HEAD -- +``` + +### Step 2 — Review each diff independently + +For each changed file, check: + +**JSpecify correctness:** +- `@NullMarked` is present at the class level +- No redundant `@NonNull` annotations remain +- `@Nullable` is used where null is genuinely possible, not speculatively +- `` only used when callers truly need nullable + type arguments +- Builder inner classes are marked `@NullUnmarked` and nothing more + +**GraphQL spec compliance:** +Fetch https://spec.graphql.org/draft/ for the relevant concept. +`MUST` = non-null. Conditional/IF = nullable. +Does the annotation match the spec? + +**Unused imports:** +Are there leftover imports (e.g. `org.jetbrains.annotations.NotNull`)? + +### Step 3 — Fix any issues found + +Make the minimal fix directly in the file. +Do NOT revert the whole annotation — fix only the specific problem. +Do NOT modify `JSpecifyAnnotationsCheck.groovy`. + +If you make any fixes, commit with: +``` +"Review fixes: correct JSpecify annotations for ClassName" +``` + +### Step 4 — Run the compile check + +``` +./gradlew compileJava +``` + +If it passes, report success and stop. + +If it fails: +- Read the NullAway error output carefully +- Make the smallest possible fix (prefer `assertNotNull(x, "message")` + over restructuring code) +- Re-run `./gradlew compileJava` +- Repeat until it passes or you have tried 3 times +- If still failing after 3 attempts, report the error details to the + orchestrator so it can decide whether to continue to the next wave + +--- + +## Validator Agent Instructions + +All waves are complete and the reviewer has confirmed `compileJava` passes +for each wave. Your job is cleanup and push only. + +1. Read the current exemption list from `JSpecifyAnnotationsCheck.groovy` +2. For each class that now has `@NullMarked` in its source file, remove it + from the `JSPECIFY_EXEMPTION_LIST` in `JSpecifyAnnotationsCheck.groovy` +3. Run `./gradlew compileJava` one final time to confirm the full build passes +4. Commit: `"Remove annotated classes from JSpecify exemption list"` +5. Push: `git push -u origin claude/agent-team-jspecify-Frd74` + +--- + +## Repository Details +- Working directory: `/home/user/graphql-java` +- Branch: `claude/agent-team-jspecify-Frd74` +- NullAway compile check: `./gradlew compileJava` From b30585a310632ad5e9903db6f6bf5d1549974bf2 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:23:43 +1100 Subject: [PATCH 02/71] Move to .claude folder --- .../commands/jspecify-team-prompt.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename jspecify-team-prompt.md => .claude/commands/jspecify-team-prompt.md (100%) diff --git a/jspecify-team-prompt.md b/.claude/commands/jspecify-team-prompt.md similarity index 100% rename from jspecify-team-prompt.md rename to .claude/commands/jspecify-team-prompt.md From 18cd2418f5998c31239a8363dfd872f2dac1e6ad Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:34:31 +1100 Subject: [PATCH 03/71] Add JSpecify annotations to QueryComplexityCalculator --- .../java/graphql/analysis/QueryComplexityCalculator.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/graphql/analysis/QueryComplexityCalculator.java b/src/main/java/graphql/analysis/QueryComplexityCalculator.java index e16035cc7..0ec297523 100644 --- a/src/main/java/graphql/analysis/QueryComplexityCalculator.java +++ b/src/main/java/graphql/analysis/QueryComplexityCalculator.java @@ -4,6 +4,9 @@ import graphql.execution.CoercedVariables; import graphql.language.Document; import graphql.schema.GraphQLSchema; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.NullUnmarked; +import org.jspecify.annotations.Nullable; import java.util.LinkedHashMap; import java.util.Map; @@ -16,12 +19,13 @@ * into it. */ @PublicApi +@NullMarked public class QueryComplexityCalculator { private final FieldComplexityCalculator fieldComplexityCalculator; private final GraphQLSchema schema; private final Document document; - private final String operationName; + private final @Nullable String operationName; private final CoercedVariables variables; public QueryComplexityCalculator(Builder builder) { @@ -95,6 +99,7 @@ public static Builder newCalculator() { return new Builder(); } + @NullUnmarked public static class Builder { private FieldComplexityCalculator fieldComplexityCalculator; private GraphQLSchema schema; From fc88122fdd67aa1a511eb46d87d50afba0130b69 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:34:52 +1100 Subject: [PATCH 04/71] Add JSpecify annotations to AbortExecutionException --- src/main/java/graphql/execution/AbortExecutionException.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/graphql/execution/AbortExecutionException.java b/src/main/java/graphql/execution/AbortExecutionException.java index 950dfde9a..fcbfd4612 100644 --- a/src/main/java/graphql/execution/AbortExecutionException.java +++ b/src/main/java/graphql/execution/AbortExecutionException.java @@ -7,6 +7,8 @@ import graphql.GraphQLException; import graphql.PublicApi; import graphql.language.SourceLocation; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.ArrayList; import java.util.Collection; @@ -19,6 +21,7 @@ * This Exception indicates that the current execution should be aborted. */ @PublicApi +@NullMarked public class AbortExecutionException extends GraphQLException implements GraphQLError { private final List underlyingErrors; @@ -47,7 +50,7 @@ public AbortExecutionException(Throwable cause) { } @Override - public List getLocations() { + public @Nullable List getLocations() { return null; } From d71b2456a18f2f03a667ceffd8d6a86152ddab1e Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:34:54 +1100 Subject: [PATCH 05/71] Add JSpecify annotations to ConditionalNodeDecision --- .../graphql/execution/conditional/ConditionalNodeDecision.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/execution/conditional/ConditionalNodeDecision.java b/src/main/java/graphql/execution/conditional/ConditionalNodeDecision.java index 69afc6bbc..14056d70e 100644 --- a/src/main/java/graphql/execution/conditional/ConditionalNodeDecision.java +++ b/src/main/java/graphql/execution/conditional/ConditionalNodeDecision.java @@ -1,6 +1,7 @@ package graphql.execution.conditional; import graphql.ExperimentalApi; +import org.jspecify.annotations.NullMarked; /** * This callback interface allows custom implementations to decide if a field is included in a query or not. @@ -8,6 +9,7 @@ * The default `@skip / @include` is built in, but you can create your own implementations to allow you to make * decisions on whether fields are considered part of a query. */ +@NullMarked @ExperimentalApi public interface ConditionalNodeDecision { From f79e9ea950d832fd5addcc6ede454f619a6492b0 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:35:01 +1100 Subject: [PATCH 06/71] Add JSpecify annotations to AsyncExecutionStrategy --- src/main/java/graphql/execution/AsyncExecutionStrategy.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/execution/AsyncExecutionStrategy.java b/src/main/java/graphql/execution/AsyncExecutionStrategy.java index 8d1d43058..325a5829a 100644 --- a/src/main/java/graphql/execution/AsyncExecutionStrategy.java +++ b/src/main/java/graphql/execution/AsyncExecutionStrategy.java @@ -3,6 +3,7 @@ import graphql.ExecutionResult; import graphql.PublicApi; import graphql.execution.incremental.DeferredExecutionSupport; +import org.jspecify.annotations.NullMarked; import graphql.execution.instrumentation.ExecutionStrategyInstrumentationContext; import graphql.execution.instrumentation.Instrumentation; import graphql.execution.instrumentation.parameters.InstrumentationExecutionStrategyParameters; @@ -17,6 +18,7 @@ * The standard graphql execution strategy that runs fields asynchronously non-blocking. */ @PublicApi +@NullMarked public class AsyncExecutionStrategy extends AbstractAsyncExecutionStrategy { /** From 3194a436421b115c2d8b796b17291df0a777d9ff Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:35:07 +1100 Subject: [PATCH 07/71] Add JSpecify annotations to QueryComplexityInfo --- .../java/graphql/analysis/QueryComplexityInfo.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/graphql/analysis/QueryComplexityInfo.java b/src/main/java/graphql/analysis/QueryComplexityInfo.java index 29914e960..83e900205 100644 --- a/src/main/java/graphql/analysis/QueryComplexityInfo.java +++ b/src/main/java/graphql/analysis/QueryComplexityInfo.java @@ -3,17 +3,20 @@ import graphql.PublicApi; import graphql.execution.instrumentation.parameters.InstrumentationExecuteOperationParameters; import graphql.execution.instrumentation.parameters.InstrumentationValidationParameters; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import org.jspecify.annotations.NullUnmarked; /** * The query complexity info. */ @PublicApi +@NullMarked public class QueryComplexityInfo { private final int complexity; - private final InstrumentationValidationParameters instrumentationValidationParameters; - private final InstrumentationExecuteOperationParameters instrumentationExecuteOperationParameters; + private final @Nullable InstrumentationValidationParameters instrumentationValidationParameters; + private final @Nullable InstrumentationExecuteOperationParameters instrumentationExecuteOperationParameters; private QueryComplexityInfo(Builder builder) { this.complexity = builder.complexity; @@ -35,7 +38,7 @@ public int getComplexity() { * * @return the instrumentation validation parameters. */ - public InstrumentationValidationParameters getInstrumentationValidationParameters() { + public @Nullable InstrumentationValidationParameters getInstrumentationValidationParameters() { return instrumentationValidationParameters; } @@ -44,7 +47,7 @@ public InstrumentationValidationParameters getInstrumentationValidationParameter * * @return the instrumentation execute operation parameters. */ - public InstrumentationExecuteOperationParameters getInstrumentationExecuteOperationParameters() { + public @Nullable InstrumentationExecuteOperationParameters getInstrumentationExecuteOperationParameters() { return instrumentationExecuteOperationParameters; } From 119d6dda7c8fe9d36ee90516073099cbeced1ddc Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:35:10 +1100 Subject: [PATCH 08/71] Add JSpecify annotations to AsyncSerialExecutionStrategy --- .../java/graphql/execution/AsyncSerialExecutionStrategy.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/execution/AsyncSerialExecutionStrategy.java b/src/main/java/graphql/execution/AsyncSerialExecutionStrategy.java index b5ff7cd5f..b896f253f 100644 --- a/src/main/java/graphql/execution/AsyncSerialExecutionStrategy.java +++ b/src/main/java/graphql/execution/AsyncSerialExecutionStrategy.java @@ -4,6 +4,7 @@ import graphql.ExecutionResult; import graphql.PublicApi; import graphql.execution.instrumentation.Instrumentation; +import org.jspecify.annotations.NullMarked; import graphql.execution.instrumentation.InstrumentationContext; import graphql.execution.instrumentation.parameters.InstrumentationExecutionStrategyParameters; import graphql.introspection.Introspection; @@ -19,6 +20,7 @@ * See {@link AsyncExecutionStrategy} for a non-serial (parallel) execution of every field. */ @PublicApi +@NullMarked public class AsyncSerialExecutionStrategy extends AbstractAsyncExecutionStrategy { public AsyncSerialExecutionStrategy() { From ce144ba1e537cad64c674c523a6dd39064c4e02e Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:35:16 +1100 Subject: [PATCH 09/71] Add JSpecify annotations to QueryDepthInfo --- src/main/java/graphql/analysis/QueryDepthInfo.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/analysis/QueryDepthInfo.java b/src/main/java/graphql/analysis/QueryDepthInfo.java index a8d4a0ac0..329c2dd49 100644 --- a/src/main/java/graphql/analysis/QueryDepthInfo.java +++ b/src/main/java/graphql/analysis/QueryDepthInfo.java @@ -1,12 +1,14 @@ package graphql.analysis; import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.NullUnmarked; /** * The query depth info. */ @PublicApi +@NullMarked public class QueryDepthInfo { private final int depth; From 7765059b93551ce00ba863de1d30b5bfe2b7001b Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:35:23 +1100 Subject: [PATCH 10/71] Add JSpecify annotations to CoercedVariables --- src/main/java/graphql/execution/CoercedVariables.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/graphql/execution/CoercedVariables.java b/src/main/java/graphql/execution/CoercedVariables.java index 6123aeec8..b567b017e 100644 --- a/src/main/java/graphql/execution/CoercedVariables.java +++ b/src/main/java/graphql/execution/CoercedVariables.java @@ -3,6 +3,8 @@ import graphql.PublicApi; import graphql.collect.ImmutableKit; import graphql.collect.ImmutableMapWithNullValues; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Map; @@ -10,6 +12,7 @@ * Holds coerced variables, that is their values are now in a canonical form. */ @PublicApi +@NullMarked public class CoercedVariables { private static final CoercedVariables EMPTY = CoercedVariables.of(ImmutableKit.emptyMap()); private final ImmutableMapWithNullValues coercedVariables; @@ -26,7 +29,7 @@ public boolean containsKey(String key) { return coercedVariables.containsKey(key); } - public Object get(String key) { + public @Nullable Object get(String key) { return coercedVariables.get(key); } From 7c8569a7785ffd428a35d62ec390e26f9087678c Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:35:26 +1100 Subject: [PATCH 11/71] Add JSpecify annotations to QueryReducer --- src/main/java/graphql/analysis/QueryReducer.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/analysis/QueryReducer.java b/src/main/java/graphql/analysis/QueryReducer.java index f19ee7fd9..e62aee415 100644 --- a/src/main/java/graphql/analysis/QueryReducer.java +++ b/src/main/java/graphql/analysis/QueryReducer.java @@ -1,6 +1,7 @@ package graphql.analysis; import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; /** * Used by {@link QueryTraverser} to reduce the fields of a Document (or part of it) to a single value. @@ -10,6 +11,7 @@ * See {@link QueryTraverser#reducePostOrder(QueryReducer, Object)} and {@link QueryTraverser#reducePreOrder(QueryReducer, Object)} */ @PublicApi +@NullMarked @FunctionalInterface public interface QueryReducer { From 6801331b829b8c50eed8a820bdd35eeba6617501 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:35:28 +1100 Subject: [PATCH 12/71] Add JSpecify annotations to QueryAppliedDirective --- .../graphql/execution/directives/QueryAppliedDirective.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/graphql/execution/directives/QueryAppliedDirective.java b/src/main/java/graphql/execution/directives/QueryAppliedDirective.java index 84492143f..d4c7785b9 100644 --- a/src/main/java/graphql/execution/directives/QueryAppliedDirective.java +++ b/src/main/java/graphql/execution/directives/QueryAppliedDirective.java @@ -7,7 +7,8 @@ import graphql.schema.GraphQLArgument; import graphql.schema.GraphQLDirective; import graphql.schema.GraphqlTypeBuilder; -import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.NullUnmarked; import org.jspecify.annotations.Nullable; import java.util.Collection; @@ -32,6 +33,7 @@ *

* See https://graphql.org/learn/queries/#directives for more details on the concept. */ +@NullMarked @PublicApi public class QueryAppliedDirective { @@ -47,7 +49,6 @@ private QueryAppliedDirective(String name, Directive definition, Collection { private final Map arguments = new LinkedHashMap<>(); From 603516756f0bc708b29fd6bf1ef59869038a2c52 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:35:34 +1100 Subject: [PATCH 13/71] Add JSpecify annotations to DataFetcherExceptionHandlerParameters --- .../execution/DataFetcherExceptionHandlerParameters.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/graphql/execution/DataFetcherExceptionHandlerParameters.java b/src/main/java/graphql/execution/DataFetcherExceptionHandlerParameters.java index b17e3582b..34faeab35 100644 --- a/src/main/java/graphql/execution/DataFetcherExceptionHandlerParameters.java +++ b/src/main/java/graphql/execution/DataFetcherExceptionHandlerParameters.java @@ -4,6 +4,8 @@ import graphql.language.SourceLocation; import graphql.schema.DataFetchingEnvironment; import graphql.schema.GraphQLFieldDefinition; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.NullUnmarked; import java.util.Map; @@ -11,6 +13,7 @@ * The parameters available to {@link DataFetcherExceptionHandler}s */ @PublicApi +@NullMarked public class DataFetcherExceptionHandlerParameters { private final DataFetchingEnvironment dataFetchingEnvironment; @@ -53,6 +56,7 @@ public static Builder newExceptionParameters() { return new Builder(); } + @NullUnmarked public static class Builder { DataFetchingEnvironment dataFetchingEnvironment; Throwable exception; From dfae148234607e8081883a4afe6f00405fa86f5e Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:35:45 +1100 Subject: [PATCH 14/71] Add JSpecify annotations to DataFetcherExceptionHandlerResult --- .../graphql/execution/DataFetcherExceptionHandlerResult.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/graphql/execution/DataFetcherExceptionHandlerResult.java b/src/main/java/graphql/execution/DataFetcherExceptionHandlerResult.java index 4059e9182..f05115e3e 100644 --- a/src/main/java/graphql/execution/DataFetcherExceptionHandlerResult.java +++ b/src/main/java/graphql/execution/DataFetcherExceptionHandlerResult.java @@ -2,6 +2,8 @@ import graphql.GraphQLError; import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.NullUnmarked; import java.util.ArrayList; import java.util.List; @@ -12,6 +14,7 @@ * The result object for {@link graphql.execution.DataFetcherExceptionHandler}s */ @PublicApi +@NullMarked public class DataFetcherExceptionHandlerResult { private final List errors; @@ -32,6 +35,7 @@ public static Builder newResult(GraphQLError error) { return new Builder().error(error); } + @NullUnmarked public static class Builder { private final List errors = new ArrayList<>(); From 460ee6b454811d26c24f160530e297d32318dba9 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:35:52 +1100 Subject: [PATCH 15/71] Add JSpecify annotations to QueryTransformer --- src/main/java/graphql/analysis/QueryTransformer.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/analysis/QueryTransformer.java b/src/main/java/graphql/analysis/QueryTransformer.java index fbf5052a9..b1a8b63c2 100644 --- a/src/main/java/graphql/analysis/QueryTransformer.java +++ b/src/main/java/graphql/analysis/QueryTransformer.java @@ -13,6 +13,7 @@ import java.util.LinkedHashMap; import java.util.Map; +import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.NullUnmarked; import static graphql.Assert.assertNotNull; @@ -31,6 +32,7 @@ * visitField calls. */ @PublicApi +@NullMarked public class QueryTransformer { private final Node root; From 4427846d967568b82d861d3a608a8a96194c8204 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:35:56 +1100 Subject: [PATCH 16/71] Add JSpecify annotations to DefaultValueUnboxer --- src/main/java/graphql/execution/DefaultValueUnboxer.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/graphql/execution/DefaultValueUnboxer.java b/src/main/java/graphql/execution/DefaultValueUnboxer.java index db03d1cfa..b763ce11a 100644 --- a/src/main/java/graphql/execution/DefaultValueUnboxer.java +++ b/src/main/java/graphql/execution/DefaultValueUnboxer.java @@ -2,6 +2,8 @@ import graphql.Internal; import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Optional; import java.util.OptionalDouble; @@ -12,16 +14,17 @@ * Public API because it should be used as a delegate when implementing a custom {@link ValueUnboxer} */ @PublicApi +@NullMarked public class DefaultValueUnboxer implements ValueUnboxer { @Override - public Object unbox(final Object object) { + public @Nullable Object unbox(final Object object) { return unboxValue(object); } @Internal // used by next-gen at the moment - public static Object unboxValue(Object result) { + public static @Nullable Object unboxValue(Object result) { if (result instanceof Optional) { Optional optional = (Optional) result; return optional.orElse(null); From 32ecef7c4f3506918e2989f7c66aa329cd984870 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:35:57 +1100 Subject: [PATCH 17/71] Add JSpecify annotations to QueryAppliedDirectiveArgument --- .../directives/QueryAppliedDirectiveArgument.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/graphql/execution/directives/QueryAppliedDirectiveArgument.java b/src/main/java/graphql/execution/directives/QueryAppliedDirectiveArgument.java index 8b772e91f..16708cedd 100644 --- a/src/main/java/graphql/execution/directives/QueryAppliedDirectiveArgument.java +++ b/src/main/java/graphql/execution/directives/QueryAppliedDirectiveArgument.java @@ -10,7 +10,8 @@ import graphql.schema.GraphQLInputType; import graphql.schema.GraphqlTypeBuilder; import graphql.schema.InputValueWithState; -import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.NullUnmarked; import org.jspecify.annotations.Nullable; import java.util.Locale; @@ -25,6 +26,7 @@ *

* You can think of them as 'instances' of {@link GraphQLArgument}, when applied to a directive on a query element */ +@NullMarked @PublicApi public class QueryAppliedDirectiveArgument { @@ -47,12 +49,10 @@ private QueryAppliedDirectiveArgument(String name, this.definition = definition; } - @NonNull public String getName() { return name; } - @NonNull public GraphQLInputType getType() { return originalType; } @@ -64,7 +64,7 @@ public boolean hasSetValue() { /** * @return an input value with state for an applied directive argument */ - public @NonNull InputValueWithState getArgumentValue() { + public InputValueWithState getArgumentValue() { return value; } @@ -134,6 +134,7 @@ public String toString() { '}'; } + @NullUnmarked public static class Builder extends GraphqlTypeBuilder { private InputValueWithState value = InputValueWithState.NOT_SET; From f223706780b0ed261976840c833b6a0ec2a40fd3 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:35:59 +1100 Subject: [PATCH 18/71] Add JSpecify annotations to QueryTraversalOptions --- src/main/java/graphql/analysis/QueryTraversalOptions.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/analysis/QueryTraversalOptions.java b/src/main/java/graphql/analysis/QueryTraversalOptions.java index 7ce73f05c..6c4a798da 100644 --- a/src/main/java/graphql/analysis/QueryTraversalOptions.java +++ b/src/main/java/graphql/analysis/QueryTraversalOptions.java @@ -1,11 +1,13 @@ package graphql.analysis; import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; /** * This options object controls how {@link QueryTraverser} works */ @PublicApi +@NullMarked public class QueryTraversalOptions { private final boolean coerceFieldArguments; From bfe03d0b9f70eecda98e952f93ee44c95a891279 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:36:10 +1100 Subject: [PATCH 19/71] Add JSpecify annotations to QueryVisitor --- src/main/java/graphql/analysis/QueryVisitor.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/analysis/QueryVisitor.java b/src/main/java/graphql/analysis/QueryVisitor.java index 69d86f244..262c59161 100644 --- a/src/main/java/graphql/analysis/QueryVisitor.java +++ b/src/main/java/graphql/analysis/QueryVisitor.java @@ -2,6 +2,7 @@ import graphql.PublicApi; import graphql.util.TraversalControl; +import org.jspecify.annotations.NullMarked; /** * Used by {@link QueryTraverser} to visit the nodes of a Query. @@ -9,6 +10,7 @@ * How this happens in detail (pre vs post-order for example) is defined by {@link QueryTraverser}. */ @PublicApi +@NullMarked public interface QueryVisitor { void visitField(QueryVisitorFieldEnvironment queryVisitorFieldEnvironment); From 8b7d7a2bdcf1153492df3c48c0541f20f4c584a4 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:36:12 +1100 Subject: [PATCH 20/71] Add JSpecify annotations to ExecutionContext --- src/main/java/graphql/execution/ExecutionContext.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/graphql/execution/ExecutionContext.java b/src/main/java/graphql/execution/ExecutionContext.java index ac4b1a8b0..997f942f9 100644 --- a/src/main/java/graphql/execution/ExecutionContext.java +++ b/src/main/java/graphql/execution/ExecutionContext.java @@ -23,6 +23,7 @@ import graphql.util.FpKit; import graphql.util.LockKit; import org.dataloader.DataLoaderRegistry; +import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; import java.util.HashSet; @@ -36,6 +37,7 @@ @SuppressWarnings("TypeParameterUnusedInFormals") @PublicApi +@NullMarked public class ExecutionContext { private final GraphQLSchema graphQLSchema; @@ -175,7 +177,7 @@ public T getRoot() { return (T) root; } - public FragmentDefinition getFragment(String name) { + public @Nullable FragmentDefinition getFragment(String name) { return fragmentsByName.get(name); } From 1d3a502e527a3650649ef57cdffd0b365fc91bce Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:36:19 +1100 Subject: [PATCH 21/71] Add JSpecify annotations to ExecutionId --- src/main/java/graphql/execution/ExecutionId.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/execution/ExecutionId.java b/src/main/java/graphql/execution/ExecutionId.java index 40ffd3466..4812c8edd 100644 --- a/src/main/java/graphql/execution/ExecutionId.java +++ b/src/main/java/graphql/execution/ExecutionId.java @@ -3,11 +3,13 @@ import graphql.Assert; import graphql.PublicApi; import graphql.util.IdGenerator; +import org.jspecify.annotations.NullMarked; /** * This opaque identifier is used to identify a unique query execution */ @PublicApi +@NullMarked public class ExecutionId { /** From ed609782e34d98f920db81aa7acc3b594f1724b6 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:36:19 +1100 Subject: [PATCH 22/71] Add JSpecify annotations to QueryDirectives --- src/main/java/graphql/execution/directives/QueryDirectives.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/execution/directives/QueryDirectives.java b/src/main/java/graphql/execution/directives/QueryDirectives.java index 6eee9f932..ff7baf686 100644 --- a/src/main/java/graphql/execution/directives/QueryDirectives.java +++ b/src/main/java/graphql/execution/directives/QueryDirectives.java @@ -2,6 +2,7 @@ import graphql.GraphQLContext; import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; import graphql.execution.CoercedVariables; import graphql.execution.MergedField; import graphql.execution.NormalizedVariables; @@ -30,6 +31,7 @@ * * @see graphql.execution.MergedField */ +@NullMarked @PublicApi public interface QueryDirectives { From 24aa942d553e2de0752a23f276305a7be1938e6e Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:36:25 +1100 Subject: [PATCH 23/71] Add JSpecify annotations to QueryVisitorFieldArgumentEnvironment --- .../analysis/QueryVisitorFieldArgumentEnvironment.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/graphql/analysis/QueryVisitorFieldArgumentEnvironment.java b/src/main/java/graphql/analysis/QueryVisitorFieldArgumentEnvironment.java index adf31abe4..42037553a 100644 --- a/src/main/java/graphql/analysis/QueryVisitorFieldArgumentEnvironment.java +++ b/src/main/java/graphql/analysis/QueryVisitorFieldArgumentEnvironment.java @@ -7,10 +7,13 @@ import graphql.schema.GraphQLFieldDefinition; import graphql.schema.GraphQLSchema; import graphql.util.TraverserContext; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Map; @PublicApi +@NullMarked public interface QueryVisitorFieldArgumentEnvironment { GraphQLSchema getSchema(); @@ -21,7 +24,7 @@ public interface QueryVisitorFieldArgumentEnvironment { Argument getArgument(); - Object getArgumentValue(); + @Nullable Object getArgumentValue(); Map getVariables(); From d92048bf381d09b42d13418fea2dd44372c4eec7 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:36:37 +1100 Subject: [PATCH 24/71] Add JSpecify annotations to QueryVisitorFieldArgumentInputValue --- .../analysis/QueryVisitorFieldArgumentInputValue.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/graphql/analysis/QueryVisitorFieldArgumentInputValue.java b/src/main/java/graphql/analysis/QueryVisitorFieldArgumentInputValue.java index 106e596ae..01288c095 100644 --- a/src/main/java/graphql/analysis/QueryVisitorFieldArgumentInputValue.java +++ b/src/main/java/graphql/analysis/QueryVisitorFieldArgumentInputValue.java @@ -4,6 +4,8 @@ import graphql.language.Value; import graphql.schema.GraphQLInputType; import graphql.schema.GraphQLInputValueDefinition; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; /** * This describes the tree structure that forms from a argument input type, @@ -11,9 +13,10 @@ * types and hence form a tree of values. */ @PublicApi +@NullMarked public interface QueryVisitorFieldArgumentInputValue { - QueryVisitorFieldArgumentInputValue getParent(); + @Nullable QueryVisitorFieldArgumentInputValue getParent(); GraphQLInputValueDefinition getInputValueDefinition(); @@ -21,5 +24,5 @@ public interface QueryVisitorFieldArgumentInputValue { GraphQLInputType getInputType(); - Value getValue(); + @Nullable Value getValue(); } From 1ebd551d169894c96ae1759e875ba65158b2bd4a Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:36:41 +1100 Subject: [PATCH 25/71] Add JSpecify annotations to FieldValidationInstrumentation --- .../fieldvalidation/FieldValidationInstrumentation.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/execution/instrumentation/fieldvalidation/FieldValidationInstrumentation.java b/src/main/java/graphql/execution/instrumentation/fieldvalidation/FieldValidationInstrumentation.java index 408fd261b..bea5d5257 100644 --- a/src/main/java/graphql/execution/instrumentation/fieldvalidation/FieldValidationInstrumentation.java +++ b/src/main/java/graphql/execution/instrumentation/fieldvalidation/FieldValidationInstrumentation.java @@ -8,6 +8,7 @@ import graphql.execution.instrumentation.InstrumentationState; import graphql.execution.instrumentation.SimplePerformantInstrumentation; import graphql.execution.instrumentation.parameters.InstrumentationExecuteOperationParameters; +import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; import java.util.List; @@ -23,6 +24,7 @@ * * @see FieldValidation */ +@NullMarked @PublicApi public class FieldValidationInstrumentation extends SimplePerformantInstrumentation { From c3bda94ad60b05fb07c739927f448850ae587539 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:36:47 +1100 Subject: [PATCH 26/71] Add JSpecify annotations to QueryVisitorFieldArgumentValueEnvironment --- .../analysis/QueryVisitorFieldArgumentValueEnvironment.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/analysis/QueryVisitorFieldArgumentValueEnvironment.java b/src/main/java/graphql/analysis/QueryVisitorFieldArgumentValueEnvironment.java index 5da2d02e8..cf07dd1d5 100644 --- a/src/main/java/graphql/analysis/QueryVisitorFieldArgumentValueEnvironment.java +++ b/src/main/java/graphql/analysis/QueryVisitorFieldArgumentValueEnvironment.java @@ -6,10 +6,12 @@ import graphql.schema.GraphQLFieldDefinition; import graphql.schema.GraphQLSchema; import graphql.util.TraverserContext; +import org.jspecify.annotations.NullMarked; import java.util.Map; @PublicApi +@NullMarked public interface QueryVisitorFieldArgumentValueEnvironment { GraphQLSchema getSchema(); From 560b28da8d4e32a89463c42521cffec57309ce77 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:37:00 +1100 Subject: [PATCH 27/71] Add JSpecify annotations to SimpleFieldValidation --- .../instrumentation/fieldvalidation/SimpleFieldValidation.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/execution/instrumentation/fieldvalidation/SimpleFieldValidation.java b/src/main/java/graphql/execution/instrumentation/fieldvalidation/SimpleFieldValidation.java index 9f0a340f1..cebbac5dd 100644 --- a/src/main/java/graphql/execution/instrumentation/fieldvalidation/SimpleFieldValidation.java +++ b/src/main/java/graphql/execution/instrumentation/fieldvalidation/SimpleFieldValidation.java @@ -4,6 +4,7 @@ import graphql.GraphQLError; import graphql.PublicApi; import graphql.execution.ResultPath; +import org.jspecify.annotations.NullMarked; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -19,6 +20,7 @@ * Use {@link #addRule(ResultPath, java.util.function.BiFunction)} to supply the rule callbacks where * you implement your specific business logic */ +@NullMarked @PublicApi public class SimpleFieldValidation implements FieldValidation { From b540dbb3803fcd95628ec9d455015aa5b1360309 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:37:17 +1100 Subject: [PATCH 28/71] Add JSpecify annotations to InstrumentationCreateStateParameters --- .../parameters/InstrumentationCreateStateParameters.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationCreateStateParameters.java b/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationCreateStateParameters.java index da07ee266..cc045ea1c 100644 --- a/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationCreateStateParameters.java +++ b/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationCreateStateParameters.java @@ -3,10 +3,12 @@ import graphql.ExecutionInput; import graphql.PublicApi; import graphql.schema.GraphQLSchema; +import org.jspecify.annotations.NullMarked; /** * Parameters sent to {@link graphql.execution.instrumentation.Instrumentation} methods */ +@NullMarked @PublicApi public class InstrumentationCreateStateParameters { private final GraphQLSchema schema; From e54951c6f3c6a90930e70a36645c067f7713ca9d Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:37:23 +1100 Subject: [PATCH 29/71] Add JSpecify annotations to ExecutionStepInfo --- .../graphql/execution/ExecutionStepInfo.java | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/main/java/graphql/execution/ExecutionStepInfo.java b/src/main/java/graphql/execution/ExecutionStepInfo.java index 26737cd12..159f8d247 100644 --- a/src/main/java/graphql/execution/ExecutionStepInfo.java +++ b/src/main/java/graphql/execution/ExecutionStepInfo.java @@ -9,6 +9,9 @@ import graphql.schema.GraphQLObjectType; import graphql.schema.GraphQLOutputType; import graphql.schema.GraphQLTypeUtil; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.NullUnmarked; +import org.jspecify.annotations.Nullable; import java.util.Map; import java.util.function.Consumer; @@ -26,6 +29,7 @@ * type instances, so this helper class adds this information during query execution. */ @PublicApi +@NullMarked public class ExecutionStepInfo { /* @@ -56,16 +60,16 @@ public class ExecutionStepInfo { * A list element is characterized by having a path ending with an index segment. (ResultPath.isListSegment()) */ private final ResultPath path; - private final ExecutionStepInfo parent; + private final @Nullable ExecutionStepInfo parent; /** * field, fieldDefinition, fieldContainer and arguments differ per field StepInfo. *

* But for list StepInfos these properties are the same as the field returning the list. */ - private final MergedField field; - private final GraphQLFieldDefinition fieldDefinition; - private final GraphQLObjectType fieldContainer; + private final @Nullable MergedField field; + private final @Nullable GraphQLFieldDefinition fieldDefinition; + private final @Nullable GraphQLObjectType fieldContainer; private final Supplier> arguments; private ExecutionStepInfo(Builder builder) { @@ -83,10 +87,10 @@ private ExecutionStepInfo(Builder builder) { */ private ExecutionStepInfo(GraphQLOutputType type, ResultPath path, - ExecutionStepInfo parent, - MergedField field, - GraphQLFieldDefinition fieldDefinition, - GraphQLObjectType fieldContainer, + @Nullable ExecutionStepInfo parent, + @Nullable MergedField field, + @Nullable GraphQLFieldDefinition fieldDefinition, + @Nullable GraphQLObjectType fieldContainer, Supplier> arguments) { this.type = assertNotNull(type, "you must provide a graphql type"); this.path = path; @@ -104,7 +108,7 @@ private ExecutionStepInfo(GraphQLOutputType type, * * @return the GraphQLObjectType defining the {@link #getFieldDefinition()} */ - public GraphQLObjectType getObjectType() { + public @Nullable GraphQLObjectType getObjectType() { return fieldContainer; } @@ -144,7 +148,7 @@ public T getUnwrappedNonNullTypeAs() { * * @return the field definition or null if there is not one */ - public GraphQLFieldDefinition getFieldDefinition() { + public @Nullable GraphQLFieldDefinition getFieldDefinition() { return fieldDefinition; } @@ -153,7 +157,7 @@ public GraphQLFieldDefinition getFieldDefinition() { * * @return the merged fields */ - public MergedField getField() { + public @Nullable MergedField getField() { return field; } @@ -194,14 +198,14 @@ public Map getArguments() { * @return the named argument or null if it's not present */ @SuppressWarnings("unchecked") - public T getArgument(String name) { + public @Nullable T getArgument(String name) { return (T) getArguments().get(name); } /** * @return the parent type information */ - public ExecutionStepInfo getParent() { + public @Nullable ExecutionStepInfo getParent() { return parent; } @@ -278,6 +282,7 @@ public static ExecutionStepInfo.Builder newExecutionStepInfo(ExecutionStepInfo e return new Builder(existing); } + @NullUnmarked public static class Builder { GraphQLOutputType type; ExecutionStepInfo parentInfo; From f9c46df05208808e901e9efda80dee38d02d0f83 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:37:32 +1100 Subject: [PATCH 30/71] Add JSpecify annotations to QueryVisitorFieldEnvironment --- .../graphql/analysis/QueryVisitorFieldEnvironment.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/graphql/analysis/QueryVisitorFieldEnvironment.java b/src/main/java/graphql/analysis/QueryVisitorFieldEnvironment.java index 608c5205d..4e98b8794 100644 --- a/src/main/java/graphql/analysis/QueryVisitorFieldEnvironment.java +++ b/src/main/java/graphql/analysis/QueryVisitorFieldEnvironment.java @@ -9,10 +9,13 @@ import graphql.schema.GraphQLOutputType; import graphql.schema.GraphQLSchema; import graphql.util.TraverserContext; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Map; @PublicApi +@NullMarked public interface QueryVisitorFieldEnvironment { /** @@ -46,11 +49,11 @@ public interface QueryVisitorFieldEnvironment { */ GraphQLFieldsContainer getFieldsContainer(); - QueryVisitorFieldEnvironment getParentEnvironment(); + @Nullable QueryVisitorFieldEnvironment getParentEnvironment(); Map getArguments(); - SelectionSetContainer getSelectionSetContainer(); + @Nullable SelectionSetContainer getSelectionSetContainer(); TraverserContext getTraverserContext(); } From f99d27bc0642e704a6c0e6f47a3fb5df8d1e9850 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:37:32 +1100 Subject: [PATCH 31/71] Add JSpecify annotations to InstrumentationExecuteOperationParameters --- .../parameters/InstrumentationExecuteOperationParameters.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationExecuteOperationParameters.java b/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationExecuteOperationParameters.java index 69587f3f4..0f8bb54c0 100644 --- a/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationExecuteOperationParameters.java +++ b/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationExecuteOperationParameters.java @@ -3,10 +3,12 @@ import graphql.PublicApi; import graphql.execution.ExecutionContext; import graphql.execution.instrumentation.Instrumentation; +import org.jspecify.annotations.NullMarked; /** * Parameters sent to {@link Instrumentation} methods */ +@NullMarked @SuppressWarnings("TypeParameterUnusedInFormals") @PublicApi public class InstrumentationExecuteOperationParameters { From 52a1a5635d34e7263df9c230bc7feecf7f7e9c1d Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:37:40 +1100 Subject: [PATCH 32/71] Add JSpecify annotations to QueryVisitorFragmentDefinitionEnvironment --- .../analysis/QueryVisitorFragmentDefinitionEnvironment.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/analysis/QueryVisitorFragmentDefinitionEnvironment.java b/src/main/java/graphql/analysis/QueryVisitorFragmentDefinitionEnvironment.java index da9ab1560..cf7a20af8 100644 --- a/src/main/java/graphql/analysis/QueryVisitorFragmentDefinitionEnvironment.java +++ b/src/main/java/graphql/analysis/QueryVisitorFragmentDefinitionEnvironment.java @@ -5,8 +5,10 @@ import graphql.language.Node; import graphql.schema.GraphQLSchema; import graphql.util.TraverserContext; +import org.jspecify.annotations.NullMarked; @PublicApi +@NullMarked public interface QueryVisitorFragmentDefinitionEnvironment { /** From 6caa99bef3e5a9b47f54018f7a4198f5ca68f4fb Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:37:46 +1100 Subject: [PATCH 33/71] Add JSpecify annotations to QueryVisitorFragmentSpreadEnvironment --- .../graphql/analysis/QueryVisitorFragmentSpreadEnvironment.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/analysis/QueryVisitorFragmentSpreadEnvironment.java b/src/main/java/graphql/analysis/QueryVisitorFragmentSpreadEnvironment.java index 4d70f2475..d4318a392 100644 --- a/src/main/java/graphql/analysis/QueryVisitorFragmentSpreadEnvironment.java +++ b/src/main/java/graphql/analysis/QueryVisitorFragmentSpreadEnvironment.java @@ -6,8 +6,10 @@ import graphql.language.Node; import graphql.schema.GraphQLSchema; import graphql.util.TraverserContext; +import org.jspecify.annotations.NullMarked; @PublicApi +@NullMarked public interface QueryVisitorFragmentSpreadEnvironment { /** From 37f4c59919f4ad83a5be5e80b51764c98a4c5974 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:37:52 +1100 Subject: [PATCH 34/71] Add JSpecify annotations to QueryVisitorInlineFragmentEnvironment --- .../graphql/analysis/QueryVisitorInlineFragmentEnvironment.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/analysis/QueryVisitorInlineFragmentEnvironment.java b/src/main/java/graphql/analysis/QueryVisitorInlineFragmentEnvironment.java index 699b5b453..2295b635e 100644 --- a/src/main/java/graphql/analysis/QueryVisitorInlineFragmentEnvironment.java +++ b/src/main/java/graphql/analysis/QueryVisitorInlineFragmentEnvironment.java @@ -5,8 +5,10 @@ import graphql.language.Node; import graphql.schema.GraphQLSchema; import graphql.util.TraverserContext; +import org.jspecify.annotations.NullMarked; @PublicApi +@NullMarked public interface QueryVisitorInlineFragmentEnvironment { /** From 87e0c39890467b10bd16ee150e076be29efd1f95 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:38:00 +1100 Subject: [PATCH 35/71] Add JSpecify annotations to QueryVisitorStub --- src/main/java/graphql/analysis/QueryVisitorStub.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/analysis/QueryVisitorStub.java b/src/main/java/graphql/analysis/QueryVisitorStub.java index 72129f296..0180e635e 100644 --- a/src/main/java/graphql/analysis/QueryVisitorStub.java +++ b/src/main/java/graphql/analysis/QueryVisitorStub.java @@ -1,8 +1,10 @@ package graphql.analysis; import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; @PublicApi +@NullMarked public class QueryVisitorStub implements QueryVisitor { From a559997db3c977cde71fe2666c36a7dfe8194354 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:38:00 +1100 Subject: [PATCH 36/71] Add JSpecify annotations to InstrumentationExecutionParameters --- .../parameters/InstrumentationExecutionParameters.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationExecutionParameters.java b/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationExecutionParameters.java index 58ad4d5ae..285a3116b 100644 --- a/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationExecutionParameters.java +++ b/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationExecutionParameters.java @@ -6,18 +6,21 @@ import graphql.collect.ImmutableKit; import graphql.execution.instrumentation.Instrumentation; import graphql.schema.GraphQLSchema; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Map; /** * Parameters sent to {@link Instrumentation} methods */ +@NullMarked @PublicApi public class InstrumentationExecutionParameters { private final ExecutionInput executionInput; private final String query; - private final String operation; - private final Object context; + private final @Nullable String operation; + private final @Nullable Object context; private final GraphQLContext graphQLContext; private final Map variables; private final GraphQLSchema schema; @@ -41,6 +44,7 @@ public String getQuery() { return query; } + @Nullable public String getOperation() { return operation; } @@ -54,7 +58,7 @@ public String getOperation() { */ @Deprecated(since = "2021-07-05") @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) - public T getContext() { + public @Nullable T getContext() { return (T) context; } From fd7834ce10456ae3dfa7693a1aabc4fe0724ffc4 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:38:17 +1100 Subject: [PATCH 37/71] Add JSpecify annotations to InstrumentationExecutionStrategyParameters --- .../parameters/InstrumentationExecutionStrategyParameters.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationExecutionStrategyParameters.java b/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationExecutionStrategyParameters.java index 9c93c84d4..f3503a0b3 100644 --- a/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationExecutionStrategyParameters.java +++ b/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationExecutionStrategyParameters.java @@ -3,10 +3,12 @@ import graphql.PublicApi; import graphql.execution.ExecutionContext; import graphql.execution.ExecutionStrategyParameters; +import org.jspecify.annotations.NullMarked; /** * Parameters sent to {@link graphql.execution.instrumentation.Instrumentation} methods */ +@NullMarked @PublicApi public class InstrumentationExecutionStrategyParameters { From 760c0333873c836d8e608cdbba67f474634d2f28 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:38:20 +1100 Subject: [PATCH 38/71] Add JSpecify annotations to ExecutionStrategyParameters --- .../ExecutionStrategyParameters.java | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/src/main/java/graphql/execution/ExecutionStrategyParameters.java b/src/main/java/graphql/execution/ExecutionStrategyParameters.java index 71d7fd9f8..21b828b7d 100644 --- a/src/main/java/graphql/execution/ExecutionStrategyParameters.java +++ b/src/main/java/graphql/execution/ExecutionStrategyParameters.java @@ -3,6 +3,8 @@ import graphql.Internal; import graphql.PublicApi; import graphql.execution.incremental.AlternativeCallContext; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.NullUnmarked; import org.jspecify.annotations.Nullable; import java.util.function.Consumer; @@ -13,26 +15,27 @@ * The parameters that are passed to execution strategies */ @PublicApi +@NullMarked public class ExecutionStrategyParameters { private final ExecutionStepInfo executionStepInfo; - private final Object source; - private final Object localContext; + private final @Nullable Object source; + private final @Nullable Object localContext; private final MergedSelectionSet fields; private final NonNullableFieldValidator nonNullableFieldValidator; private final ResultPath path; - private final MergedField currentField; - private final ExecutionStrategyParameters parent; - private final AlternativeCallContext alternativeCallContext; + private final @Nullable MergedField currentField; + private final @Nullable ExecutionStrategyParameters parent; + private final @Nullable AlternativeCallContext alternativeCallContext; private ExecutionStrategyParameters(ExecutionStepInfo executionStepInfo, - Object source, - Object localContext, + @Nullable Object source, + @Nullable Object localContext, MergedSelectionSet fields, NonNullableFieldValidator nonNullableFieldValidator, ResultPath path, - MergedField currentField, - ExecutionStrategyParameters parent, - AlternativeCallContext alternativeCallContext) { + @Nullable MergedField currentField, + @Nullable ExecutionStrategyParameters parent, + @Nullable AlternativeCallContext alternativeCallContext) { this.executionStepInfo = assertNotNull(executionStepInfo, "executionStepInfo is null"); this.localContext = localContext; @@ -49,7 +52,7 @@ public ExecutionStepInfo getExecutionStepInfo() { return executionStepInfo; } - public Object getSource() { + public @Nullable Object getSource() { return source; } @@ -65,11 +68,11 @@ public ResultPath getPath() { return path; } - public Object getLocalContext() { + public @Nullable Object getLocalContext() { return localContext; } - public ExecutionStrategyParameters getParent() { + public @Nullable ExecutionStrategyParameters getParent() { return parent; } @@ -113,7 +116,7 @@ public boolean isInDeferredContext() { * * @return the current merged fields */ - public MergedField getField() { + public @Nullable MergedField getField() { return currentField; } @@ -134,7 +137,7 @@ ExecutionStrategyParameters transform(MergedField currentField, @Internal ExecutionStrategyParameters transform(ExecutionStepInfo executionStepInfo, MergedSelectionSet fields, - Object source) { + @Nullable Object source) { return new ExecutionStrategyParameters(executionStepInfo, source, localContext, @@ -149,8 +152,8 @@ ExecutionStrategyParameters transform(ExecutionStepInfo executionStepInfo, @Internal ExecutionStrategyParameters transform(ExecutionStepInfo executionStepInfo, ResultPath path, - Object localContext, - Object source) { + @Nullable Object localContext, + @Nullable Object source) { return new ExecutionStrategyParameters(executionStepInfo, source, localContext, @@ -164,8 +167,8 @@ ExecutionStrategyParameters transform(ExecutionStepInfo executionStepInfo, @Internal ExecutionStrategyParameters transform(ExecutionStepInfo executionStepInfo, - Object localContext, - Object source) { + @Nullable Object localContext, + @Nullable Object source) { return new ExecutionStrategyParameters(executionStepInfo, source, localContext, @@ -212,6 +215,7 @@ public static Builder newParameters(ExecutionStrategyParameters oldParameters) { return new Builder(oldParameters); } + @NullUnmarked public static class Builder { ExecutionStepInfo executionStepInfo; Object source; From 0a64cb3f75c7b575d697e37215dbefc8055f1a71 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:38:37 +1100 Subject: [PATCH 39/71] Add JSpecify annotations to InstrumentationFieldCompleteParameters --- .../InstrumentationFieldCompleteParameters.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationFieldCompleteParameters.java b/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationFieldCompleteParameters.java index ac7e1b27e..0c4107a9c 100644 --- a/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationFieldCompleteParameters.java +++ b/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationFieldCompleteParameters.java @@ -5,20 +5,23 @@ import graphql.execution.ExecutionStepInfo; import graphql.execution.ExecutionStrategyParameters; import graphql.schema.GraphQLFieldDefinition; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.function.Supplier; /** * Parameters sent to {@link graphql.execution.instrumentation.Instrumentation} methods */ +@NullMarked @PublicApi public class InstrumentationFieldCompleteParameters { private final ExecutionContext executionContext; private final Supplier executionStepInfo; - private final Object fetchedValue; + private final @Nullable Object fetchedValue; private final ExecutionStrategyParameters executionStrategyParameters; - public InstrumentationFieldCompleteParameters(ExecutionContext executionContext, ExecutionStrategyParameters executionStrategyParameters, Supplier executionStepInfo, Object fetchedValue) { + public InstrumentationFieldCompleteParameters(ExecutionContext executionContext, ExecutionStrategyParameters executionStrategyParameters, Supplier executionStepInfo, @Nullable Object fetchedValue) { this.executionContext = executionContext; this.executionStrategyParameters = executionStrategyParameters; this.executionStepInfo = executionStepInfo; @@ -54,6 +57,7 @@ public ExecutionStepInfo getExecutionStepInfo() { * * @return the object was fetched, ready to be completed as a value. */ + @Nullable public Object getFetchedObject() { return fetchedValue; } From 452969072d7195148fe8597a03eaa97424177455 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:38:51 +1100 Subject: [PATCH 40/71] Add JSpecify annotations to FetchedValue --- .../java/graphql/execution/FetchedValue.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/main/java/graphql/execution/FetchedValue.java b/src/main/java/graphql/execution/FetchedValue.java index fe56fa0a1..b4b5f0387 100644 --- a/src/main/java/graphql/execution/FetchedValue.java +++ b/src/main/java/graphql/execution/FetchedValue.java @@ -4,6 +4,8 @@ import graphql.GraphQLError; import graphql.PublicApi; import graphql.execution.instrumentation.parameters.InstrumentationFieldCompleteParameters; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.List; @@ -12,9 +14,10 @@ * and therefore part of the public despite never used in a method signature. */ @PublicApi +@NullMarked public class FetchedValue { - private final Object fetchedValue; - private final Object localContext; + private final @Nullable Object fetchedValue; + private final @Nullable Object localContext; private final ImmutableList errors; /** @@ -25,7 +28,7 @@ public class FetchedValue { * * @return the {@link FetchedValue#getFetchedValue()} if its wrapped otherwise the source value itself */ - public static Object getFetchedValue(Object sourceValue) { + public static @Nullable Object getFetchedValue(@Nullable Object sourceValue) { if (sourceValue instanceof FetchedValue) { return ((FetchedValue) sourceValue).fetchedValue; } else { @@ -42,7 +45,7 @@ public static Object getFetchedValue(Object sourceValue) { * * @return the {@link FetchedValue#getFetchedValue()} if its wrapped otherwise the default local context */ - public static Object getLocalContext(Object sourceValue, Object defaultLocalContext) { + public static @Nullable Object getLocalContext(@Nullable Object sourceValue, @Nullable Object defaultLocalContext) { if (sourceValue instanceof FetchedValue) { return ((FetchedValue) sourceValue).localContext; } else { @@ -50,7 +53,7 @@ public static Object getLocalContext(Object sourceValue, Object defaultLocalCont } } - public FetchedValue(Object fetchedValue, List errors, Object localContext) { + public FetchedValue(@Nullable Object fetchedValue, List errors, @Nullable Object localContext) { this.fetchedValue = fetchedValue; this.errors = ImmutableList.copyOf(errors); this.localContext = localContext; @@ -59,7 +62,7 @@ public FetchedValue(Object fetchedValue, List errors, Object local /* * the unboxed value meaning not Optional, not DataFetcherResult etc */ - public Object getFetchedValue() { + public @Nullable Object getFetchedValue() { return fetchedValue; } @@ -67,7 +70,7 @@ public List getErrors() { return errors; } - public Object getLocalContext() { + public @Nullable Object getLocalContext() { return localContext; } From 6286c17d24a9deff8739c90cd9b04f7cd8a1796f Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:38:55 +1100 Subject: [PATCH 41/71] Add JSpecify annotations to InstrumentationFieldFetchParameters --- .../parameters/InstrumentationFieldFetchParameters.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationFieldFetchParameters.java b/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationFieldFetchParameters.java index fda194d73..5db11a737 100644 --- a/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationFieldFetchParameters.java +++ b/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationFieldFetchParameters.java @@ -5,12 +5,14 @@ import graphql.execution.ExecutionStrategyParameters; import graphql.execution.instrumentation.Instrumentation; import graphql.schema.DataFetchingEnvironment; +import org.jspecify.annotations.NullMarked; import java.util.function.Supplier; /** * Parameters sent to {@link Instrumentation} methods */ +@NullMarked @PublicApi public class InstrumentationFieldFetchParameters extends InstrumentationFieldParameters { private final Supplier environment; From 8df475db192fa2f70833887ce4c1e1cc89054a0a Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:39:11 +1100 Subject: [PATCH 42/71] Add JSpecify annotations to InstrumentationFieldParameters --- .../parameters/InstrumentationFieldParameters.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationFieldParameters.java b/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationFieldParameters.java index ebac32ffb..5e1604b87 100644 --- a/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationFieldParameters.java +++ b/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationFieldParameters.java @@ -5,12 +5,14 @@ import graphql.execution.ExecutionStepInfo; import graphql.execution.instrumentation.Instrumentation; import graphql.schema.GraphQLFieldDefinition; +import org.jspecify.annotations.NullMarked; import java.util.function.Supplier; /** * Parameters sent to {@link Instrumentation} methods */ +@NullMarked @PublicApi public class InstrumentationFieldParameters { private final ExecutionContext executionContext; From 1f8ce617b172feb0b3816185edb89dc817f5da91 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:39:22 +1100 Subject: [PATCH 43/71] Add JSpecify annotations to FieldValueInfo --- src/main/java/graphql/execution/FieldValueInfo.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/graphql/execution/FieldValueInfo.java b/src/main/java/graphql/execution/FieldValueInfo.java index 2839a8cd5..0108503bc 100644 --- a/src/main/java/graphql/execution/FieldValueInfo.java +++ b/src/main/java/graphql/execution/FieldValueInfo.java @@ -2,6 +2,8 @@ import com.google.common.collect.ImmutableList; import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -19,6 +21,7 @@ * values might need a call to a database or other systems will tend to be {@link CompletableFuture} promises. */ @PublicApi +@NullMarked public class FieldValueInfo { public enum CompleteValueType { @@ -30,14 +33,14 @@ public enum CompleteValueType { } private final CompleteValueType completeValueType; - private final Object /* CompletableFuture | Object */ fieldValueObject; + private final @Nullable Object /* CompletableFuture | Object */ fieldValueObject; private final List fieldValueInfos; - public FieldValueInfo(CompleteValueType completeValueType, Object fieldValueObject) { + public FieldValueInfo(CompleteValueType completeValueType, @Nullable Object fieldValueObject) { this(completeValueType, fieldValueObject, ImmutableList.of()); } - public FieldValueInfo(CompleteValueType completeValueType, Object fieldValueObject, List fieldValueInfos) { + public FieldValueInfo(CompleteValueType completeValueType, @Nullable Object fieldValueObject, List fieldValueInfos) { assertNotNull(fieldValueInfos, "fieldValueInfos can't be null"); this.completeValueType = completeValueType; this.fieldValueObject = fieldValueObject; @@ -58,7 +61,7 @@ public CompleteValueType getCompleteValueType() { * * @return either an object that is materialized or a {@link CompletableFuture} promise to a value */ - public Object /* CompletableFuture | Object */ getFieldValueObject() { + public @Nullable Object /* CompletableFuture | Object */ getFieldValueObject() { return fieldValueObject; } From 63677a1f1ed146fba5dff7c2cd3266ecf3b6b45a Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:39:29 +1100 Subject: [PATCH 44/71] Add JSpecify annotations to InstrumentationValidationParameters --- .../parameters/InstrumentationValidationParameters.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationValidationParameters.java b/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationValidationParameters.java index c23a41394..21257df54 100644 --- a/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationValidationParameters.java +++ b/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationValidationParameters.java @@ -5,10 +5,12 @@ import graphql.execution.instrumentation.Instrumentation; import graphql.language.Document; import graphql.schema.GraphQLSchema; +import org.jspecify.annotations.NullMarked; /** * Parameters sent to {@link Instrumentation} methods */ +@NullMarked @PublicApi public class InstrumentationValidationParameters extends InstrumentationExecutionParameters { private final Document document; From bea66791a312f48145b95142ed43770df0481f56 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:39:43 +1100 Subject: [PATCH 45/71] Add JSpecify annotations to InputMapDefinesTooManyFieldsException --- .../execution/InputMapDefinesTooManyFieldsException.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/graphql/execution/InputMapDefinesTooManyFieldsException.java b/src/main/java/graphql/execution/InputMapDefinesTooManyFieldsException.java index 654c069c3..e4aef7e2c 100644 --- a/src/main/java/graphql/execution/InputMapDefinesTooManyFieldsException.java +++ b/src/main/java/graphql/execution/InputMapDefinesTooManyFieldsException.java @@ -7,6 +7,8 @@ import graphql.language.SourceLocation; import graphql.schema.GraphQLType; import graphql.schema.GraphQLTypeUtil; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.List; @@ -16,6 +18,7 @@ * - This unordered map should not contain any entries with names not defined by a field of this input object type, otherwise an error should be thrown. */ @PublicApi +@NullMarked public class InputMapDefinesTooManyFieldsException extends GraphQLException implements GraphQLError { public InputMapDefinesTooManyFieldsException(GraphQLType graphQLType, String fieldName) { @@ -23,7 +26,7 @@ public InputMapDefinesTooManyFieldsException(GraphQLType graphQLType, String fie } @Override - public List getLocations() { + public @Nullable List getLocations() { return null; } From 0b6534cc1787d0751052820441844799e9bf3f98 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:39:55 +1100 Subject: [PATCH 46/71] Add JSpecify annotations to TracingInstrumentation --- .../instrumentation/tracing/TracingInstrumentation.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/graphql/execution/instrumentation/tracing/TracingInstrumentation.java b/src/main/java/graphql/execution/instrumentation/tracing/TracingInstrumentation.java index ed18f68ab..f522ed154 100644 --- a/src/main/java/graphql/execution/instrumentation/tracing/TracingInstrumentation.java +++ b/src/main/java/graphql/execution/instrumentation/tracing/TracingInstrumentation.java @@ -14,7 +14,7 @@ import graphql.execution.instrumentation.parameters.InstrumentationValidationParameters; import graphql.language.Document; import graphql.validation.ValidationError; -import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; import java.util.LinkedHashMap; @@ -29,6 +29,7 @@ * This {@link Instrumentation} implementation uses {@link TracingSupport} to * capture tracing information and puts it into the {@link ExecutionResult} */ +@NullMarked @PublicApi public class TracingInstrumentation extends SimplePerformantInstrumentation { @@ -77,7 +78,7 @@ public TracingInstrumentation(Options options) { } @Override - public @NonNull CompletableFuture instrumentExecutionResult(ExecutionResult executionResult, InstrumentationExecutionParameters parameters, InstrumentationState rawState) { + public CompletableFuture instrumentExecutionResult(ExecutionResult executionResult, InstrumentationExecutionParameters parameters, InstrumentationState rawState) { Map currentExt = executionResult.getExtensions(); TracingSupport tracingSupport = ofState(rawState); From 7197bd9d985366aadbddd8111315ef8a8f8294dd Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:39:56 +1100 Subject: [PATCH 47/71] Add JSpecify annotations to ValueTraverser --- .../analysis/values/ValueTraverser.java | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/main/java/graphql/analysis/values/ValueTraverser.java b/src/main/java/graphql/analysis/values/ValueTraverser.java index 664cda26b..b935c2c53 100644 --- a/src/main/java/graphql/analysis/values/ValueTraverser.java +++ b/src/main/java/graphql/analysis/values/ValueTraverser.java @@ -19,6 +19,8 @@ import graphql.schema.GraphQLNonNull; import graphql.schema.GraphQLScalarType; import graphql.schema.GraphQLTypeUtil; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.LinkedHashMap; import java.util.List; @@ -46,13 +48,14 @@ * null values for non-nullable types say, so you need to be careful. */ @PublicApi +@NullMarked public class ValueTraverser { private static class InputElements implements ValueVisitor.InputElements { private final ImmutableList inputElements; private final List unwrappedInputElements; - private final GraphQLInputValueDefinition lastElement; + private final @Nullable GraphQLInputValueDefinition lastElement; private InputElements(GraphQLInputSchemaElement startElement) { this.inputElements = ImmutableList.of(startElement); @@ -88,7 +91,7 @@ public List getUnwrappedInputElements() { } @Override - public GraphQLInputValueDefinition getLastInputValueDefinition() { + public @Nullable GraphQLInputValueDefinition getLastInputValueDefinition() { return lastElement; } } @@ -161,7 +164,7 @@ public static Map visitPreOrder(Map coercedArgum * * @return the same value if nothing changes or a new value if the visitor changes anything */ - public static Object visitPreOrder(Object coercedArgumentValue, GraphQLArgument argument, ValueVisitor visitor) { + public static @Nullable Object visitPreOrder(@Nullable Object coercedArgumentValue, GraphQLArgument argument, ValueVisitor visitor) { InputElements inputElements = new InputElements(argument); Object newValue = visitor.visitArgumentValue(coercedArgumentValue, argument, inputElements); if (newValue == ABSENCE_SENTINEL) { @@ -185,7 +188,7 @@ public static Object visitPreOrder(Object coercedArgumentValue, GraphQLArgument * * @return the same value if nothing changes or a new value if the visitor changes anything */ - public static Object visitPreOrder(Object coercedArgumentValue, GraphQLAppliedDirectiveArgument argument, ValueVisitor visitor) { + public static @Nullable Object visitPreOrder(@Nullable Object coercedArgumentValue, GraphQLAppliedDirectiveArgument argument, ValueVisitor visitor) { InputElements inputElements = new InputElements(argument); Object newValue = visitor.visitAppliedDirectiveArgumentValue(coercedArgumentValue, argument, inputElements); if (newValue == ABSENCE_SENTINEL) { @@ -198,7 +201,7 @@ public static Object visitPreOrder(Object coercedArgumentValue, GraphQLAppliedDi return newValue; } - private static Object visitPreOrderImpl(Object coercedValue, GraphQLInputType startingInputType, InputElements containingElements, ValueVisitor visitor) { + private static @Nullable Object visitPreOrderImpl(@Nullable Object coercedValue, GraphQLInputType startingInputType, InputElements containingElements, ValueVisitor visitor) { if (startingInputType instanceof GraphQLNonNull) { containingElements = containingElements.push(startingInputType); } @@ -218,7 +221,7 @@ private static Object visitPreOrderImpl(Object coercedValue, GraphQLInputType st } } - private static Object visitObjectValue(Object coercedValue, GraphQLInputObjectType inputObjectType, InputElements containingElements, ValueVisitor visitor) { + private static @Nullable Object visitObjectValue(@Nullable Object coercedValue, GraphQLInputObjectType inputObjectType, InputElements containingElements, ValueVisitor visitor) { if (coercedValue != null) { assertTrue(coercedValue instanceof Map, "A input object type MUST have an Map value"); } @@ -263,7 +266,7 @@ private static Object visitObjectValue(Object coercedValue, GraphQLInputObjectTy } } - private static Object visitListValue(Object coercedValue, GraphQLList listInputType, InputElements containingElements, ValueVisitor visitor) { + private static @Nullable Object visitListValue(@Nullable Object coercedValue, GraphQLList listInputType, InputElements containingElements, ValueVisitor visitor) { if (coercedValue != null) { assertTrue(coercedValue instanceof List, "A list type MUST have an List value"); } @@ -306,11 +309,11 @@ private static Object visitListValue(Object coercedValue, GraphQLList listInputT } } - private static boolean hasChanged(Object newValue, Object oldValue) { + private static boolean hasChanged(@Nullable Object newValue, @Nullable Object oldValue) { return newValue != oldValue || newValue == ABSENCE_SENTINEL; } - private static void setNewValue(Map newMap, String key, Object newValue) { + private static void setNewValue(Map newMap, String key, @Nullable Object newValue) { if (newValue == ABSENCE_SENTINEL) { newMap.remove(key); } else { From 016e5608e434ddd772e2cdf9899b5a51116f2925 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:40:00 +1100 Subject: [PATCH 48/71] Add JSpecify annotations to MergedSelectionSet --- src/main/java/graphql/execution/MergedSelectionSet.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/graphql/execution/MergedSelectionSet.java b/src/main/java/graphql/execution/MergedSelectionSet.java index 434b8da4f..75b7df45a 100644 --- a/src/main/java/graphql/execution/MergedSelectionSet.java +++ b/src/main/java/graphql/execution/MergedSelectionSet.java @@ -3,6 +3,9 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.NullUnmarked; +import org.jspecify.annotations.Nullable; import java.util.List; import java.util.Map; @@ -10,6 +13,7 @@ @PublicApi +@NullMarked public class MergedSelectionSet { private final Map subFields; @@ -36,7 +40,7 @@ public Set keySet() { return subFields.keySet(); } - public MergedField getSubField(String key) { + public @Nullable MergedField getSubField(String key) { return subFields.get(key); } @@ -52,6 +56,7 @@ public static Builder newMergedSelectionSet() { return new Builder(); } + @NullUnmarked public static class Builder { private Map subFields; From d372306cf04430487c68e68b305808e1319d0e39 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:40:10 +1100 Subject: [PATCH 49/71] Add JSpecify annotations to MissingRootTypeException --- .../java/graphql/execution/MissingRootTypeException.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/graphql/execution/MissingRootTypeException.java b/src/main/java/graphql/execution/MissingRootTypeException.java index 9662f69ec..7ae68cbb3 100644 --- a/src/main/java/graphql/execution/MissingRootTypeException.java +++ b/src/main/java/graphql/execution/MissingRootTypeException.java @@ -8,21 +8,24 @@ import graphql.GraphQLException; import graphql.PublicApi; import graphql.language.SourceLocation; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; /** * This is thrown if a query is attempting to perform an operation not defined in the GraphQL schema */ @PublicApi +@NullMarked public class MissingRootTypeException extends GraphQLException implements GraphQLError { - private List sourceLocations; + private @Nullable List sourceLocations; - public MissingRootTypeException(String message, SourceLocation sourceLocation) { + public MissingRootTypeException(String message, @Nullable SourceLocation sourceLocation) { super(message); this.sourceLocations = sourceLocation == null ? null : Collections.singletonList(sourceLocation); } @Override - public List getLocations() { + public @Nullable List getLocations() { return sourceLocations; } From 9063da8301b17e5044de932a1197f88c1a95b773 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:40:22 +1100 Subject: [PATCH 50/71] Add JSpecify annotations to TracingSupport --- .../execution/instrumentation/tracing/TracingSupport.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/execution/instrumentation/tracing/TracingSupport.java b/src/main/java/graphql/execution/instrumentation/tracing/TracingSupport.java index 4a0f97a15..8328f154d 100644 --- a/src/main/java/graphql/execution/instrumentation/tracing/TracingSupport.java +++ b/src/main/java/graphql/execution/instrumentation/tracing/TracingSupport.java @@ -5,6 +5,7 @@ import graphql.execution.ExecutionStepInfo; import graphql.execution.instrumentation.InstrumentationState; import graphql.schema.DataFetchingEnvironment; +import org.jspecify.annotations.NullMarked; import java.time.Instant; import java.time.format.DateTimeFormatter; @@ -22,6 +23,7 @@ * calls. It has been made a separate class so that you can compose this into existing * instrumentation code. */ +@NullMarked @PublicApi public class TracingSupport implements InstrumentationState { From df504d29b07121c086c9186e663015da39e0cef7 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:40:27 +1100 Subject: [PATCH 51/71] Add JSpecify annotations to NonNullableValueCoercedAsNullException --- .../NonNullableValueCoercedAsNullException.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/graphql/execution/NonNullableValueCoercedAsNullException.java b/src/main/java/graphql/execution/NonNullableValueCoercedAsNullException.java index 4dfb68081..9192d5080 100644 --- a/src/main/java/graphql/execution/NonNullableValueCoercedAsNullException.java +++ b/src/main/java/graphql/execution/NonNullableValueCoercedAsNullException.java @@ -10,6 +10,8 @@ import graphql.schema.GraphQLInputObjectField; import graphql.schema.GraphQLType; import graphql.schema.GraphQLTypeUtil; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Collections; import java.util.List; @@ -20,9 +22,10 @@ * This is thrown if a non nullable value is coerced to a null value */ @PublicApi +@NullMarked public class NonNullableValueCoercedAsNullException extends GraphQLException implements GraphQLError { - private List sourceLocations; - private List path; + private @Nullable List sourceLocations; + private @Nullable List path; public NonNullableValueCoercedAsNullException(VariableDefinition variableDefinition, GraphQLType graphQLType) { super(format("Variable '%s' has coerced Null value for NonNull type '%s'", @@ -74,12 +77,12 @@ public NonNullableValueCoercedAsNullException(GraphQLArgument graphQLArgument) { } @Override - public List getLocations() { + public @Nullable List getLocations() { return sourceLocations; } @Override - public List getPath() { + public @Nullable List getPath() { return path; } From bc5689fc269bcc840c9411ebf60f7a86c95cbdb9 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:40:40 +1100 Subject: [PATCH 52/71] Add JSpecify annotations to NormalizedVariables --- src/main/java/graphql/execution/NormalizedVariables.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/graphql/execution/NormalizedVariables.java b/src/main/java/graphql/execution/NormalizedVariables.java index ef16fec3c..59b1d905b 100644 --- a/src/main/java/graphql/execution/NormalizedVariables.java +++ b/src/main/java/graphql/execution/NormalizedVariables.java @@ -4,6 +4,8 @@ import graphql.collect.ImmutableKit; import graphql.collect.ImmutableMapWithNullValues; import graphql.normalized.NormalizedInputValue; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Map; @@ -11,6 +13,7 @@ * Holds coerced variables, that is their values are now in a normalized {@link graphql.normalized.NormalizedInputValue} form. */ @PublicApi +@NullMarked public class NormalizedVariables { private final ImmutableMapWithNullValues normalisedVariables; @@ -26,7 +29,7 @@ public boolean containsKey(String key) { return normalisedVariables.containsKey(key); } - public Object get(String key) { + public @Nullable Object get(String key) { return normalisedVariables.get(key); } From 9de2bea747553dfe631f995aacbadbed91699b84 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:40:42 +1100 Subject: [PATCH 53/71] Add JSpecify annotations to PreparsedDocumentEntry --- .../execution/preparsed/PreparsedDocumentEntry.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/graphql/execution/preparsed/PreparsedDocumentEntry.java b/src/main/java/graphql/execution/preparsed/PreparsedDocumentEntry.java index 8c14cf9bf..114ee6240 100644 --- a/src/main/java/graphql/execution/preparsed/PreparsedDocumentEntry.java +++ b/src/main/java/graphql/execution/preparsed/PreparsedDocumentEntry.java @@ -3,6 +3,8 @@ import graphql.GraphQLError; import graphql.PublicApi; import graphql.language.Document; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.io.Serializable; import java.util.List; @@ -20,10 +22,11 @@ * with times frames that cross graphql-java versions. While we don't change things unnecessarily, we may inadvertently break * the serialised compatibility across versions. */ +@NullMarked @PublicApi public class PreparsedDocumentEntry implements Serializable { - private final Document document; - private final List errors; + private final @Nullable Document document; + private final @Nullable List errors; public PreparsedDocumentEntry(Document document, List errors) { @@ -49,10 +52,12 @@ public PreparsedDocumentEntry(GraphQLError error) { this(singletonList(assertNotNull(error))); } + @Nullable public Document getDocument() { return document; } + @Nullable public List getErrors() { return errors; } From 4b69632e13956419a8f50cfbf3374cdd5dd76ca6 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:40:50 +1100 Subject: [PATCH 54/71] Add JSpecify annotations to OneOfNullValueException --- src/main/java/graphql/execution/OneOfNullValueException.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/graphql/execution/OneOfNullValueException.java b/src/main/java/graphql/execution/OneOfNullValueException.java index 40e5bbcca..cc9d3da82 100644 --- a/src/main/java/graphql/execution/OneOfNullValueException.java +++ b/src/main/java/graphql/execution/OneOfNullValueException.java @@ -5,6 +5,8 @@ import graphql.GraphQLException; import graphql.PublicApi; import graphql.language.SourceLocation; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.List; @@ -12,6 +14,7 @@ * The input map to One Of Input Types MUST only have 1 entry with a non null value */ @PublicApi +@NullMarked public class OneOfNullValueException extends GraphQLException implements GraphQLError { public OneOfNullValueException(String message) { @@ -19,7 +22,7 @@ public OneOfNullValueException(String message) { } @Override - public List getLocations() { + public @Nullable List getLocations() { return null; } From 8bb5d4096abb084d7f958ef1a97fdeb2cc261f85 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:40:56 +1100 Subject: [PATCH 55/71] Add JSpecify annotations to ApolloPersistedQuerySupport --- .../preparsed/persisted/ApolloPersistedQuerySupport.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/execution/preparsed/persisted/ApolloPersistedQuerySupport.java b/src/main/java/graphql/execution/preparsed/persisted/ApolloPersistedQuerySupport.java index b7b1a1530..68162bbc2 100644 --- a/src/main/java/graphql/execution/preparsed/persisted/ApolloPersistedQuerySupport.java +++ b/src/main/java/graphql/execution/preparsed/persisted/ApolloPersistedQuerySupport.java @@ -2,6 +2,7 @@ import graphql.ExecutionInput; import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; import java.math.BigInteger; import java.nio.charset.StandardCharsets; @@ -33,6 +34,7 @@ * * @see graphql.ExecutionInput#getExtensions() */ +@NullMarked @PublicApi public class ApolloPersistedQuerySupport extends PersistedQuerySupport { From 11d09ceadf00092b0c08899b7a3c6407bb314158 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:41:08 +1100 Subject: [PATCH 56/71] Add JSpecify annotations to OneOfTooManyKeysException --- .../java/graphql/execution/OneOfTooManyKeysException.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/graphql/execution/OneOfTooManyKeysException.java b/src/main/java/graphql/execution/OneOfTooManyKeysException.java index f8d3c0053..50ff017b1 100644 --- a/src/main/java/graphql/execution/OneOfTooManyKeysException.java +++ b/src/main/java/graphql/execution/OneOfTooManyKeysException.java @@ -5,6 +5,8 @@ import graphql.GraphQLException; import graphql.PublicApi; import graphql.language.SourceLocation; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.List; @@ -12,6 +14,7 @@ * The input map to One Of Input Types MUST only have 1 entry */ @PublicApi +@NullMarked public class OneOfTooManyKeysException extends GraphQLException implements GraphQLError { public OneOfTooManyKeysException(String message) { @@ -19,7 +22,7 @@ public OneOfTooManyKeysException(String message) { } @Override - public List getLocations() { + public @Nullable List getLocations() { return null; } From 3d4e99f9269414905543ba98fdc05be8afe36e55 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:41:15 +1100 Subject: [PATCH 57/71] Add JSpecify annotations to InMemoryPersistedQueryCache --- .../preparsed/persisted/InMemoryPersistedQueryCache.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/graphql/execution/preparsed/persisted/InMemoryPersistedQueryCache.java b/src/main/java/graphql/execution/preparsed/persisted/InMemoryPersistedQueryCache.java index 5226332b8..18000e509 100644 --- a/src/main/java/graphql/execution/preparsed/persisted/InMemoryPersistedQueryCache.java +++ b/src/main/java/graphql/execution/preparsed/persisted/InMemoryPersistedQueryCache.java @@ -4,6 +4,8 @@ import graphql.ExecutionInput; import graphql.PublicApi; import graphql.execution.preparsed.PreparsedDocumentEntry; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.NullUnmarked; import java.util.HashMap; import java.util.Map; @@ -13,6 +15,7 @@ /** * A PersistedQueryCache that is just an in memory map of known queries. */ +@NullMarked @PublicApi public class InMemoryPersistedQueryCache implements PersistedQueryCache { @@ -53,6 +56,7 @@ public static Builder newInMemoryPersistedQueryCache() { return new Builder(); } + @NullUnmarked public static class Builder { private final Map knownQueries = new HashMap<>(); From 1154e30a241a4d86dc83af6b33e676f44676bf89 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:41:18 +1100 Subject: [PATCH 58/71] Add JSpecify annotations to ResultNodesInfo --- src/main/java/graphql/execution/ResultNodesInfo.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/execution/ResultNodesInfo.java b/src/main/java/graphql/execution/ResultNodesInfo.java index afc366f6b..9e8b3cfec 100644 --- a/src/main/java/graphql/execution/ResultNodesInfo.java +++ b/src/main/java/graphql/execution/ResultNodesInfo.java @@ -2,6 +2,7 @@ import graphql.Internal; import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; import java.util.concurrent.atomic.AtomicInteger; @@ -14,6 +15,7 @@ *

*/ @PublicApi +@NullMarked public class ResultNodesInfo { public static final String MAX_RESULT_NODES = "__MAX_RESULT_NODES"; From 45ed448be6b9a897b227b5933ccc78c2ebafcc5f Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:41:31 +1100 Subject: [PATCH 59/71] Add JSpecify annotations to PersistedQueryCacheMiss --- .../execution/preparsed/persisted/PersistedQueryCacheMiss.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/execution/preparsed/persisted/PersistedQueryCacheMiss.java b/src/main/java/graphql/execution/preparsed/persisted/PersistedQueryCacheMiss.java index 6e9cc03a3..285c0c78a 100644 --- a/src/main/java/graphql/execution/preparsed/persisted/PersistedQueryCacheMiss.java +++ b/src/main/java/graphql/execution/preparsed/persisted/PersistedQueryCacheMiss.java @@ -2,6 +2,7 @@ import graphql.PublicApi; import graphql.execution.preparsed.PreparsedDocumentEntry; +import org.jspecify.annotations.NullMarked; import java.util.function.Function; @@ -10,6 +11,7 @@ * by the graphql engine. If you get a cache miss in your {@link graphql.execution.preparsed.persisted.PersistedQueryCache} implementation * then you are required to call back on the provided instance of this interface */ +@NullMarked @PublicApi public interface PersistedQueryCacheMiss extends Function { /** From d7d5a82398415cdf807703d2fab43056caf56ea3 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:41:54 +1100 Subject: [PATCH 60/71] Add JSpecify annotations to PersistedQueryIdInvalid --- .../execution/preparsed/persisted/PersistedQueryIdInvalid.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/execution/preparsed/persisted/PersistedQueryIdInvalid.java b/src/main/java/graphql/execution/preparsed/persisted/PersistedQueryIdInvalid.java index 259906979..120022ceb 100644 --- a/src/main/java/graphql/execution/preparsed/persisted/PersistedQueryIdInvalid.java +++ b/src/main/java/graphql/execution/preparsed/persisted/PersistedQueryIdInvalid.java @@ -1,10 +1,12 @@ package graphql.execution.preparsed.persisted; import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; import java.util.LinkedHashMap; import java.util.Map; +@NullMarked @PublicApi public class PersistedQueryIdInvalid extends PersistedQueryError { private final Object persistedQueryId; From 100c2cd63b8728012920eeb91012e64cdc23bcb8 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:42:10 +1100 Subject: [PATCH 61/71] Add JSpecify annotations to PersistedQueryNotFound --- .../execution/preparsed/persisted/PersistedQueryNotFound.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/execution/preparsed/persisted/PersistedQueryNotFound.java b/src/main/java/graphql/execution/preparsed/persisted/PersistedQueryNotFound.java index 22c38bf8e..14ff2968c 100644 --- a/src/main/java/graphql/execution/preparsed/persisted/PersistedQueryNotFound.java +++ b/src/main/java/graphql/execution/preparsed/persisted/PersistedQueryNotFound.java @@ -1,6 +1,7 @@ package graphql.execution.preparsed.persisted; import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; import java.util.LinkedHashMap; import java.util.Map; @@ -8,6 +9,7 @@ /** * An exception that indicates the query id is not valid and can be found ever in cache */ +@NullMarked @PublicApi public class PersistedQueryNotFound extends PersistedQueryError { private final Object persistedQueryId; From 4c004a1603117bb52f0408fbe1f629f9d6146b2d Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:42:20 +1100 Subject: [PATCH 62/71] Add JSpecify annotations to ResultPath --- .../java/graphql/execution/ResultPath.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/main/java/graphql/execution/ResultPath.java b/src/main/java/graphql/execution/ResultPath.java index 20d13f139..ba517a4dc 100644 --- a/src/main/java/graphql/execution/ResultPath.java +++ b/src/main/java/graphql/execution/ResultPath.java @@ -4,6 +4,8 @@ import graphql.AssertException; import graphql.PublicApi; import graphql.collect.ImmutableKit; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.ArrayList; import java.util.LinkedList; @@ -21,6 +23,7 @@ * class represents that path as a series of segments. */ @PublicApi +@NullMarked public class ResultPath { private static final ResultPath ROOT_PATH = new ResultPath(); @@ -33,13 +36,13 @@ public static ResultPath rootPath() { return ROOT_PATH; } - private final ResultPath parent; - private final Object segment; + private final @Nullable ResultPath parent; + private final @Nullable Object segment; // hash is effective immutable but lazily initialized similar to the hash code of java.lang.String private int hash; // lazily initialized similar to hash - computed on first toString() call - private String toStringValue; + private @Nullable String toStringValue; private final int level; private ResultPath() { @@ -72,7 +75,7 @@ public int getLevel() { return level; } - public ResultPath getPathWithoutListEnd() { + public @Nullable ResultPath getPathWithoutListEnd() { if (ROOT_PATH.equals(this)) { return ROOT_PATH; } @@ -105,11 +108,11 @@ public int getSegmentIndex() { return (int) segment; } - public Object getSegmentValue() { + public @Nullable Object getSegmentValue() { return segment; } - public ResultPath getParent() { + public @Nullable ResultPath getParent() { return parent; } @@ -120,7 +123,7 @@ public ResultPath getParent() { * * @return a parsed execution path */ - public static ResultPath parse(String pathString) { + public static ResultPath parse(@Nullable String pathString) { pathString = pathString == null ? "" : pathString; String finalPathString = pathString.trim(); StringTokenizer st = new StringTokenizer(finalPathString, "/[]", true); @@ -195,7 +198,7 @@ public ResultPath segment(int segment) { * * @return a new path with the last segment dropped off */ - public ResultPath dropSegment() { + public @Nullable ResultPath dropSegment() { if (this == rootPath()) { return null; } From 3e190f3e864e3ad763b73457d35bfbfcf25db7fa Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:42:24 +1100 Subject: [PATCH 63/71] Add JSpecify annotations to DelegatingSubscription --- .../java/graphql/execution/reactive/DelegatingSubscription.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/execution/reactive/DelegatingSubscription.java b/src/main/java/graphql/execution/reactive/DelegatingSubscription.java index e8a3ff9df..3f51f690c 100644 --- a/src/main/java/graphql/execution/reactive/DelegatingSubscription.java +++ b/src/main/java/graphql/execution/reactive/DelegatingSubscription.java @@ -1,6 +1,7 @@ package graphql.execution.reactive; import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; import org.reactivestreams.Subscription; import static graphql.Assert.assertNotNull; @@ -8,6 +9,7 @@ /** * A simple subscription that delegates to another */ +@NullMarked @PublicApi public class DelegatingSubscription implements Subscription { private final Subscription upstreamSubscription; From e54044027027d4dfeefd02b10e16a7c22e61121d Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:42:31 +1100 Subject: [PATCH 64/71] Add JSpecify annotations to SimpleDataFetcherExceptionHandler --- .../graphql/execution/SimpleDataFetcherExceptionHandler.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/execution/SimpleDataFetcherExceptionHandler.java b/src/main/java/graphql/execution/SimpleDataFetcherExceptionHandler.java index 79e201a33..adfb4d078 100644 --- a/src/main/java/graphql/execution/SimpleDataFetcherExceptionHandler.java +++ b/src/main/java/graphql/execution/SimpleDataFetcherExceptionHandler.java @@ -3,6 +3,7 @@ import graphql.ExceptionWhileDataFetching; import graphql.PublicApi; import graphql.language.SourceLocation; +import org.jspecify.annotations.NullMarked; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; @@ -12,6 +13,7 @@ * into the error collection */ @PublicApi +@NullMarked public class SimpleDataFetcherExceptionHandler implements DataFetcherExceptionHandler { static final SimpleDataFetcherExceptionHandler defaultImpl = new SimpleDataFetcherExceptionHandler(); From e9fd9e9f5d1416bea80c1923622b70f0a9055f7d Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:42:39 +1100 Subject: [PATCH 65/71] Add JSpecify annotations to SubscriptionPublisher --- .../java/graphql/execution/reactive/SubscriptionPublisher.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/execution/reactive/SubscriptionPublisher.java b/src/main/java/graphql/execution/reactive/SubscriptionPublisher.java index 4951b451d..e3fbf5bd9 100644 --- a/src/main/java/graphql/execution/reactive/SubscriptionPublisher.java +++ b/src/main/java/graphql/execution/reactive/SubscriptionPublisher.java @@ -3,6 +3,7 @@ import graphql.ExecutionResult; import graphql.Internal; import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; import org.reactivestreams.Publisher; import org.reactivestreams.Subscriber; @@ -21,6 +22,7 @@ * } * */ +@NullMarked @SuppressWarnings("ReactiveStreamsPublisherImplementation") @PublicApi public class SubscriptionPublisher implements Publisher { From 76f195cf2c354f3bb78342822ab96490d63a3bdc Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:42:47 +1100 Subject: [PATCH 66/71] Add JSpecify annotations to SubscriptionExecutionStrategy --- .../graphql/execution/SubscriptionExecutionStrategy.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/graphql/execution/SubscriptionExecutionStrategy.java b/src/main/java/graphql/execution/SubscriptionExecutionStrategy.java index f1e1a9a91..f8aaa702b 100644 --- a/src/main/java/graphql/execution/SubscriptionExecutionStrategy.java +++ b/src/main/java/graphql/execution/SubscriptionExecutionStrategy.java @@ -5,6 +5,8 @@ import graphql.ExecutionResultImpl; import graphql.GraphQLContext; import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import graphql.execution.incremental.AlternativeCallContext; import graphql.execution.instrumentation.ExecutionStrategyInstrumentationContext; import graphql.execution.instrumentation.Instrumentation; @@ -40,6 +42,7 @@ * See https://www.reactive-streams.org/ */ @PublicApi +@NullMarked public class SubscriptionExecutionStrategy extends ExecutionStrategy { /** @@ -132,7 +135,7 @@ private CompletableFuture> createSourceEventStream(ExecutionCo * @return a reactive streams {@link Publisher} always */ @SuppressWarnings("unchecked") - private static Publisher mkReactivePublisher(Object publisherObj) { + private static @Nullable Publisher mkReactivePublisher(@Nullable Object publisherObj) { if (publisherObj != null) { if (publisherObj instanceof Publisher) { return (Publisher) publisherObj; From 9db1bde85fff292ff697e838b92d272333bfac97 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:42:59 +1100 Subject: [PATCH 67/71] Add JSpecify annotations to UnknownOperationException --- .../java/graphql/execution/UnknownOperationException.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/graphql/execution/UnknownOperationException.java b/src/main/java/graphql/execution/UnknownOperationException.java index 6ef523c9b..13f427dff 100644 --- a/src/main/java/graphql/execution/UnknownOperationException.java +++ b/src/main/java/graphql/execution/UnknownOperationException.java @@ -6,6 +6,8 @@ import graphql.GraphQLException; import graphql.PublicApi; import graphql.language.SourceLocation; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.List; @@ -15,13 +17,14 @@ * contained in the GraphQL query. */ @PublicApi +@NullMarked public class UnknownOperationException extends GraphQLException implements GraphQLError { public UnknownOperationException(String message) { super(message); } @Override - public List getLocations() { + public @Nullable List getLocations() { return null; } From 2529914f8945b3f226a9c71458a490b0b1c55862 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:43:14 +1100 Subject: [PATCH 68/71] Add JSpecify annotations to UnresolvedTypeException --- src/main/java/graphql/execution/UnresolvedTypeException.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/execution/UnresolvedTypeException.java b/src/main/java/graphql/execution/UnresolvedTypeException.java index 4a6aad47d..f964affb2 100644 --- a/src/main/java/graphql/execution/UnresolvedTypeException.java +++ b/src/main/java/graphql/execution/UnresolvedTypeException.java @@ -5,12 +5,14 @@ import graphql.schema.GraphQLNamedOutputType; import graphql.schema.GraphQLType; import graphql.schema.GraphQLTypeUtil; +import org.jspecify.annotations.NullMarked; /** * This is thrown if a {@link graphql.schema.TypeResolver} fails to give back a concrete type * or provides a type that doesn't implement the given interface or union. */ @PublicApi +@NullMarked public class UnresolvedTypeException extends GraphQLException { private final GraphQLNamedOutputType interfaceOrUnionType; From b3563cf624e6281b0f71ac4e85a490405f693cd1 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 10:56:50 +1100 Subject: [PATCH 69/71] Review fixes: correct JSpecify annotations for Wave 1 classes - QueryAppliedDirectiveArgument: remove @NonNull from Builder methods (import was dropped) - ResultPath: fix @Nullable parent/segment dereferences with assertNotNull - ExecutionStepInfo: fix @Nullable field dereference in getResultKey() - ExecutionContext: add assertNotNull for AtomicReference.get() calls on errors - SubscriptionExecutionStrategy: fix @Nullable getField()/getDeferredCallContext() dereferences - AsyncSerialExecutionStrategy: fix @Nullable getSubField()/getFieldValueObject() issues - DataFetcherExceptionHandlerParameters: mark getSourceLocation() @Nullable - ExceptionWhileDataFetching: accept @Nullable SourceLocation in constructor - TracingSupport/UnresolvedTypeError: fix @Nullable getParent()/getFieldDefinition() dereferences - InstrumentationFieldParameters/Complete: fix @Nullable getFieldDefinition() in getField() - ExecutionStepInfoFactory: fix @Nullable getField() with assertNotNull - GraphQL: fix @Nullable getDocument() with assertNotNull - ValueTraverser: fix @Nullable newValue passed to ImmutableList.Builder.add() - MaxQueryDepthInstrumentation: mark getPathLength() param @Nullable Co-Authored-By: Claude Sonnet 4.6 --- .../graphql/ExceptionWhileDataFetching.java | 2 +- src/main/java/graphql/GraphQL.java | 2 +- .../java/graphql/UnresolvedTypeError.java | 4 ++-- .../MaxQueryDepthInstrumentation.java | 3 ++- .../analysis/values/ValueTraverser.java | 5 +++-- .../AsyncSerialExecutionStrategy.java | 6 ++++-- ...DataFetcherExceptionHandlerParameters.java | 3 ++- .../graphql/execution/ExecutionContext.java | 10 ++++++---- .../graphql/execution/ExecutionStepInfo.java | 2 +- .../execution/ExecutionStepInfoFactory.java | 3 ++- .../java/graphql/execution/ResultPath.java | 20 +++++++++---------- .../SubscriptionExecutionStrategy.java | 9 +++++---- .../QueryAppliedDirectiveArgument.java | 4 ++-- ...nstrumentationFieldCompleteParameters.java | 4 +++- .../InstrumentationFieldParameters.java | 4 +++- .../tracing/TracingSupport.java | 5 +++-- 16 files changed, 50 insertions(+), 36 deletions(-) diff --git a/src/main/java/graphql/ExceptionWhileDataFetching.java b/src/main/java/graphql/ExceptionWhileDataFetching.java index d5d0c6137..89a13d964 100644 --- a/src/main/java/graphql/ExceptionWhileDataFetching.java +++ b/src/main/java/graphql/ExceptionWhileDataFetching.java @@ -27,7 +27,7 @@ public class ExceptionWhileDataFetching implements GraphQLError { private final List locations; private final @Nullable Map extensions; - public ExceptionWhileDataFetching(ResultPath path, Throwable exception, SourceLocation sourceLocation) { + public ExceptionWhileDataFetching(ResultPath path, Throwable exception, @Nullable SourceLocation sourceLocation) { this.path = assertNotNull(path).toList(); this.exception = assertNotNull(exception); this.locations = Collections.singletonList(sourceLocation); diff --git a/src/main/java/graphql/GraphQL.java b/src/main/java/graphql/GraphQL.java index 1441238b8..ca79ca9a4 100644 --- a/src/main/java/graphql/GraphQL.java +++ b/src/main/java/graphql/GraphQL.java @@ -547,7 +547,7 @@ private CompletableFuture parseValidateAndExecute(ExecutionInpu return CompletableFuture.completedFuture(new ExecutionResultImpl(preparsedDocumentEntry.getErrors())); } try { - return execute(Assert.assertNotNull(executionInputRef.get()), preparsedDocumentEntry.getDocument(), graphQLSchema, instrumentationState, engineRunningState, profiler); + return execute(Assert.assertNotNull(executionInputRef.get()), assertNotNull(preparsedDocumentEntry.getDocument(), "document must not be null"), graphQLSchema, instrumentationState, engineRunningState, profiler); } catch (AbortExecutionException e) { return CompletableFuture.completedFuture(e.toExecutionResult()); } diff --git a/src/main/java/graphql/UnresolvedTypeError.java b/src/main/java/graphql/UnresolvedTypeError.java index ba9bf333a..60200df15 100644 --- a/src/main/java/graphql/UnresolvedTypeError.java +++ b/src/main/java/graphql/UnresolvedTypeError.java @@ -32,8 +32,8 @@ private String mkMessage(ResultPath path, UnresolvedTypeException exception, Exe return format("Can't resolve '%s'. Abstract type '%s' must resolve to an Object type at runtime for field '%s.%s'. %s", path, exception.getInterfaceOrUnionType().getName(), - simplePrint(info.getParent().getUnwrappedNonNullType()), - info.getFieldDefinition().getName(), + simplePrint(assertNotNull(info.getParent(), "executionStepInfo parent must not be null").getUnwrappedNonNullType()), + assertNotNull(info.getFieldDefinition(), "fieldDefinition must not be null").getName(), exception.getMessage()); } diff --git a/src/main/java/graphql/analysis/MaxQueryDepthInstrumentation.java b/src/main/java/graphql/analysis/MaxQueryDepthInstrumentation.java index 1ac22227f..6bab51da1 100644 --- a/src/main/java/graphql/analysis/MaxQueryDepthInstrumentation.java +++ b/src/main/java/graphql/analysis/MaxQueryDepthInstrumentation.java @@ -9,6 +9,7 @@ import graphql.execution.instrumentation.SimplePerformantInstrumentation; import graphql.execution.instrumentation.parameters.InstrumentationExecuteOperationParameters; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.function.Function; @@ -84,7 +85,7 @@ QueryTraverser newQueryTraverser(ExecutionContext executionContext) { .build(); } - private int getPathLength(QueryVisitorFieldEnvironment path) { + private int getPathLength(@Nullable QueryVisitorFieldEnvironment path) { int length = 1; while (path != null) { path = path.getParentEnvironment(); diff --git a/src/main/java/graphql/analysis/values/ValueTraverser.java b/src/main/java/graphql/analysis/values/ValueTraverser.java index b935c2c53..0cc1c3d31 100644 --- a/src/main/java/graphql/analysis/values/ValueTraverser.java +++ b/src/main/java/graphql/analysis/values/ValueTraverser.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Map; +import static graphql.Assert.assertNotNull; import static graphql.Assert.assertShouldNeverHappen; import static graphql.Assert.assertTrue; import static graphql.analysis.values.ValueVisitor.ABSENCE_SENTINEL; @@ -284,7 +285,7 @@ public static Map visitPreOrder(Map coercedArgum Object newValue = visitPreOrderImpl(subValue, inputType, containingElements, visitor); if (copiedList != null) { if (newValue != ABSENCE_SENTINEL) { - copiedList.add(newValue); + copiedList.add(assertNotNull(newValue, "list element must not be null")); } } else if (hasChanged(newValue, subValue)) { // go into copy mode because something has changed @@ -294,7 +295,7 @@ public static Map visitPreOrder(Map coercedArgum copiedList.add(newList.get(j)); } if (newValue != ABSENCE_SENTINEL) { - copiedList.add(newValue); + copiedList.add(assertNotNull(newValue, "list element must not be null")); } } i++; diff --git a/src/main/java/graphql/execution/AsyncSerialExecutionStrategy.java b/src/main/java/graphql/execution/AsyncSerialExecutionStrategy.java index b896f253f..6c865e05a 100644 --- a/src/main/java/graphql/execution/AsyncSerialExecutionStrategy.java +++ b/src/main/java/graphql/execution/AsyncSerialExecutionStrategy.java @@ -5,6 +5,7 @@ import graphql.PublicApi; import graphql.execution.instrumentation.Instrumentation; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import graphql.execution.instrumentation.InstrumentationContext; import graphql.execution.instrumentation.parameters.InstrumentationExecutionStrategyParameters; import graphql.introspection.Introspection; @@ -13,6 +14,7 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; +import static graphql.Assert.assertNotNull; import static graphql.execution.instrumentation.SimpleInstrumentationContext.nonNullCtx; /** @@ -52,7 +54,7 @@ public CompletableFuture execute(ExecutionContext executionCont } CompletableFuture> resultsFuture = Async.eachSequentially(fieldNames, (fieldName, prevResults) -> { - MergedField currentField = fields.getSubField(fieldName); + MergedField currentField = assertNotNull(fields.getSubField(fieldName), "currentField must not be null"); ResultPath fieldPath = parameters.getPath().segment(mkNameForPath(currentField)); ExecutionStrategyParameters newParameters = parameters.transform(currentField, fieldPath); @@ -67,7 +69,7 @@ public CompletableFuture execute(ExecutionContext executionCont return overallResult; } - private Object resolveSerialField(ExecutionContext executionContext, + private @Nullable Object resolveSerialField(ExecutionContext executionContext, DataLoaderDispatchStrategy dataLoaderDispatcherStrategy, ExecutionStrategyParameters newParameters) { dataLoaderDispatcherStrategy.executionSerialStrategy(executionContext, newParameters); diff --git a/src/main/java/graphql/execution/DataFetcherExceptionHandlerParameters.java b/src/main/java/graphql/execution/DataFetcherExceptionHandlerParameters.java index 34faeab35..494f02cd5 100644 --- a/src/main/java/graphql/execution/DataFetcherExceptionHandlerParameters.java +++ b/src/main/java/graphql/execution/DataFetcherExceptionHandlerParameters.java @@ -6,6 +6,7 @@ import graphql.schema.GraphQLFieldDefinition; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.NullUnmarked; +import org.jspecify.annotations.Nullable; import java.util.Map; @@ -48,7 +49,7 @@ public Map getArgumentValues() { return dataFetchingEnvironment.getArguments(); } - public SourceLocation getSourceLocation() { + public @Nullable SourceLocation getSourceLocation() { return getField().getSingleField().getSourceLocation(); } diff --git a/src/main/java/graphql/execution/ExecutionContext.java b/src/main/java/graphql/execution/ExecutionContext.java index 997f942f9..b4e1b52ce 100644 --- a/src/main/java/graphql/execution/ExecutionContext.java +++ b/src/main/java/graphql/execution/ExecutionContext.java @@ -35,6 +35,8 @@ import java.util.function.Consumer; import java.util.function.Supplier; +import static graphql.Assert.assertNotNull; + @SuppressWarnings("TypeParameterUnusedInFormals") @PublicApi @NullMarked @@ -249,7 +251,7 @@ public void addError(GraphQLError error, ResultPath fieldPath) { if (!errorPaths.add(fieldPath)) { return; } - this.errors.set(ImmutableKit.addToList(this.errors.get(), error)); + this.errors.set(ImmutableKit.addToList(assertNotNull(this.errors.get(), "errors list must not be null"), error)); }); } @@ -268,7 +270,7 @@ public void addError(GraphQLError error) { ResultPath path = ResultPath.fromList(error.getPath()); this.errorPaths.add(path); } - this.errors.set(ImmutableKit.addToList(this.errors.get(), error)); + this.errors.set(ImmutableKit.addToList(assertNotNull(this.errors.get(), "errors list must not be null"), error)); }); } @@ -296,7 +298,7 @@ public void addErrors(List errors) { } } this.errorPaths.addAll(newErrorPaths); - this.errors.set(ImmutableKit.concatLists(this.errors.get(), errors)); + this.errors.set(ImmutableKit.concatLists(assertNotNull(this.errors.get(), "errors list must not be null"), errors)); }); } @@ -309,7 +311,7 @@ public ResponseMapFactory getResponseMapFactory() { * @return the total list of errors for this execution context */ public List getErrors() { - return errors.get(); + return assertNotNull(errors.get(), "errors list must not be null"); } public ExecutionStrategy getQueryStrategy() { diff --git a/src/main/java/graphql/execution/ExecutionStepInfo.java b/src/main/java/graphql/execution/ExecutionStepInfo.java index 159f8d247..0fecdfc49 100644 --- a/src/main/java/graphql/execution/ExecutionStepInfo.java +++ b/src/main/java/graphql/execution/ExecutionStepInfo.java @@ -268,7 +268,7 @@ public ExecutionStepInfo transform(Consumer builderConsumer) { } public String getResultKey() { - return field.getResultKey(); + return assertNotNull(field, "field must not be null").getResultKey(); } /** diff --git a/src/main/java/graphql/execution/ExecutionStepInfoFactory.java b/src/main/java/graphql/execution/ExecutionStepInfoFactory.java index 286106a7d..fc382c205 100644 --- a/src/main/java/graphql/execution/ExecutionStepInfoFactory.java +++ b/src/main/java/graphql/execution/ExecutionStepInfoFactory.java @@ -18,6 +18,7 @@ import java.util.Map; import java.util.function.Supplier; +import static graphql.Assert.assertNotNull; import static graphql.execution.ExecutionStepInfo.newExecutionStepInfo; @Internal @@ -44,7 +45,7 @@ public ExecutionStepInfo createExecutionStepInfo(ExecutionContext executionConte ExecutionStrategyParameters parameters, GraphQLFieldDefinition fieldDefinition, @Nullable GraphQLObjectType fieldContainer) { - MergedField field = parameters.getField(); + MergedField field = assertNotNull(parameters.getField(), "field must not be null"); ExecutionStepInfo parentStepInfo = parameters.getExecutionStepInfo(); GraphQLOutputType fieldType = fieldDefinition.getType(); List fieldArgDefs = fieldDefinition.getArguments(); diff --git a/src/main/java/graphql/execution/ResultPath.java b/src/main/java/graphql/execution/ResultPath.java index ba517a4dc..daa56bb41 100644 --- a/src/main/java/graphql/execution/ResultPath.java +++ b/src/main/java/graphql/execution/ResultPath.java @@ -101,11 +101,11 @@ public boolean isNamedSegment() { public String getSegmentName() { - return (String) segment; + return (String) assertNotNull(segment); } public int getSegmentIndex() { - return (int) segment; + return (int) assertNotNull(segment); } public @Nullable Object getSegmentValue() { @@ -215,7 +215,7 @@ public ResultPath segment(int segment) { */ public ResultPath replaceSegment(int segment) { assertTrue(!ROOT_PATH.equals(this), "You MUST not call this with the root path"); - return new ResultPath(parent, segment); + return new ResultPath(assertNotNull(parent, "parent must not be null for non-root path"), segment); } /** @@ -228,7 +228,7 @@ public ResultPath replaceSegment(int segment) { */ public ResultPath replaceSegment(String segment) { assertTrue(!ROOT_PATH.equals(this), "You MUST not call this with the root path"); - return new ResultPath(parent, segment); + return new ResultPath(assertNotNull(parent, "parent must not be null for non-root path"), segment); } @@ -255,12 +255,12 @@ public ResultPath append(ResultPath path) { public ResultPath sibling(String siblingField) { assertTrue(!ROOT_PATH.equals(this), "You MUST not call this with the root path"); - return new ResultPath(this.parent, siblingField); + return new ResultPath(assertNotNull(this.parent, "parent must not be null for non-root path"), siblingField); } public ResultPath sibling(int siblingField) { assertTrue(!ROOT_PATH.equals(this), "You MUST not call this with the root path"); - return new ResultPath(this.parent, siblingField); + return new ResultPath(assertNotNull(this.parent, "parent must not be null for non-root path"), siblingField); } /** @@ -274,7 +274,7 @@ public List toList() { ResultPath p = this; while (p.segment != null) { list.addFirst(p.segment); - p = p.parent; + p = assertNotNull(p.parent, "non-root ResultPath must have a non-null parent"); } return ImmutableList.copyOf(list); } @@ -292,7 +292,7 @@ public List getKeysOnly() { if (p.segment instanceof String) { list.addFirst((String) p.segment); } - p = p.parent; + p = assertNotNull(p.parent, "non-root ResultPath must have a non-null parent"); } return list; } @@ -334,8 +334,8 @@ public boolean equals(Object o) { if (!Objects.equals(self.segment, that.segment)) { return false; } - self = self.parent; - that = that.parent; + self = assertNotNull(self.parent, "non-root ResultPath must have a non-null parent"); + that = assertNotNull(that.parent, "non-root ResultPath must have a non-null parent"); } return self.isRootPath() && that.isRootPath(); diff --git a/src/main/java/graphql/execution/SubscriptionExecutionStrategy.java b/src/main/java/graphql/execution/SubscriptionExecutionStrategy.java index f8aaa702b..89c77e967 100644 --- a/src/main/java/graphql/execution/SubscriptionExecutionStrategy.java +++ b/src/main/java/graphql/execution/SubscriptionExecutionStrategy.java @@ -27,6 +27,7 @@ import java.util.concurrent.Flow; import java.util.function.Function; +import static graphql.Assert.assertNotNull; import static graphql.execution.instrumentation.SimpleInstrumentationContext.nonNullCtx; import static java.util.Collections.singletonMap; @@ -185,7 +186,7 @@ private CompletableFuture executeSubscriptionEvent(ExecutionCon executionContext.getDataLoaderDispatcherStrategy().subscriptionEventCompletionDone(newParameters.getDeferredCallContext()); CompletableFuture overallResult = fieldValueInfo .getFieldValueFuture() - .thenApply(val -> new ExecutionResultImpl(val, newParameters.getDeferredCallContext().getErrors())) + .thenApply(val -> new ExecutionResultImpl(val, assertNotNull(newParameters.getDeferredCallContext(), "deferredCallContext must not be null").getErrors())) .thenApply(executionResult -> wrapWithRootFieldName(newParameters, executionResult)); // dispatch instrumentation so they can know about each subscription event @@ -209,7 +210,7 @@ private ExecutionResult wrapWithRootFieldName(ExecutionStrategyParameters parame } private String getRootFieldName(ExecutionStrategyParameters parameters) { - Field rootField = parameters.getField().getSingleField(); + Field rootField = assertNotNull(parameters.getField(), "field must not be null").getSingleField(); return rootField.getResultKey(); } @@ -217,7 +218,7 @@ private ExecutionStrategyParameters firstFieldOfSubscriptionSelection(ExecutionC ExecutionStrategyParameters parameters, boolean newCallContext) { MergedSelectionSet fields = parameters.getFields(); - MergedField firstField = fields.getSubField(fields.getKeys().get(0)); + MergedField firstField = assertNotNull(fields.getSubField(fields.getKeys().get(0)), "firstField must not be null"); ResultPath fieldPath = parameters.getPath().segment(mkNameForPath(firstField.getSingleField())); NonNullableFieldValidator nonNullableFieldValidator = new NonNullableFieldValidator(executionContext); @@ -237,7 +238,7 @@ private ExecutionStrategyParameters firstFieldOfSubscriptionSelection(ExecutionC private ExecutionStepInfo createSubscribedFieldStepInfo(ExecutionContext executionContext, ExecutionStrategyParameters parameters) { - Field field = parameters.getField().getSingleField(); + Field field = assertNotNull(parameters.getField(), "field must not be null").getSingleField(); GraphQLObjectType parentType = parameters.getExecutionStepInfo().getUnwrappedNonNullTypeAs(); GraphQLFieldDefinition fieldDef = getFieldDef(executionContext.getGraphQLSchema(), parentType, field); return createExecutionStepInfo(executionContext, parameters, fieldDef, parentType); diff --git a/src/main/java/graphql/execution/directives/QueryAppliedDirectiveArgument.java b/src/main/java/graphql/execution/directives/QueryAppliedDirectiveArgument.java index 16708cedd..98cc68be1 100644 --- a/src/main/java/graphql/execution/directives/QueryAppliedDirectiveArgument.java +++ b/src/main/java/graphql/execution/directives/QueryAppliedDirectiveArgument.java @@ -167,7 +167,7 @@ public Builder definition(Argument definition) { * * @return this builder */ - public Builder valueLiteral(@NonNull Value value) { + public Builder valueLiteral(Value value) { this.value = InputValueWithState.newLiteralValue(value); return this; } @@ -182,7 +182,7 @@ public Builder valueProgrammatic(@Nullable Object value) { return this; } - public Builder inputValueWithState(@NonNull InputValueWithState value) { + public Builder inputValueWithState(InputValueWithState value) { this.value = Assert.assertNotNull(value); return this; } diff --git a/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationFieldCompleteParameters.java b/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationFieldCompleteParameters.java index 0c4107a9c..2a49c1264 100644 --- a/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationFieldCompleteParameters.java +++ b/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationFieldCompleteParameters.java @@ -10,6 +10,8 @@ import java.util.function.Supplier; +import static graphql.Assert.assertNotNull; + /** * Parameters sent to {@link graphql.execution.instrumentation.Instrumentation} methods */ @@ -39,7 +41,7 @@ public ExecutionStrategyParameters getExecutionStrategyParameters() { } public GraphQLFieldDefinition getField() { - return getExecutionStepInfo().getFieldDefinition(); + return assertNotNull(getExecutionStepInfo().getFieldDefinition(), "fieldDefinition must not be null"); } @Deprecated(since = "2020-09-08") diff --git a/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationFieldParameters.java b/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationFieldParameters.java index 5e1604b87..5b7fcd18f 100644 --- a/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationFieldParameters.java +++ b/src/main/java/graphql/execution/instrumentation/parameters/InstrumentationFieldParameters.java @@ -9,6 +9,8 @@ import java.util.function.Supplier; +import static graphql.Assert.assertNotNull; + /** * Parameters sent to {@link Instrumentation} methods */ @@ -26,7 +28,7 @@ public ExecutionContext getExecutionContext() { } public GraphQLFieldDefinition getField() { - return executionStepInfo.get().getFieldDefinition(); + return assertNotNull(executionStepInfo.get().getFieldDefinition(), "fieldDefinition must not be null"); } public ExecutionStepInfo getExecutionStepInfo() { diff --git a/src/main/java/graphql/execution/instrumentation/tracing/TracingSupport.java b/src/main/java/graphql/execution/instrumentation/tracing/TracingSupport.java index 8328f154d..0aa5a9a93 100644 --- a/src/main/java/graphql/execution/instrumentation/tracing/TracingSupport.java +++ b/src/main/java/graphql/execution/instrumentation/tracing/TracingSupport.java @@ -14,6 +14,7 @@ import java.util.Map; import java.util.concurrent.ConcurrentLinkedQueue; +import static graphql.Assert.assertNotNull; import static graphql.schema.GraphQLTypeUtil.simplePrint; /** @@ -80,9 +81,9 @@ public TracingContext beginField(DataFetchingEnvironment dataFetchingEnvironment Map fetchMap = new LinkedHashMap<>(); fetchMap.put("path", executionStepInfo.getPath().toList()); - fetchMap.put("parentType", simplePrint(executionStepInfo.getParent().getUnwrappedNonNullType())); + fetchMap.put("parentType", simplePrint(assertNotNull(executionStepInfo.getParent(), "executionStepInfo parent must not be null").getUnwrappedNonNullType())); fetchMap.put("returnType", executionStepInfo.simplePrint()); - fetchMap.put("fieldName", executionStepInfo.getFieldDefinition().getName()); + fetchMap.put("fieldName", assertNotNull(executionStepInfo.getFieldDefinition(), "fieldDefinition must not be null").getName()); fetchMap.put("startOffset", startOffset); fetchMap.put("duration", duration); From 30581c89101cb275004f3e14dd26748ec42d6367 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 15:45:18 +1100 Subject: [PATCH 70/71] Remove annotated Wave 1 classes from JSpecify exemption list All 66 classes annotated in Wave 1 (graphql.analysis, graphql.execution core, and graphql.execution sub-packages) are removed from the exemption list now that they carry @NullMarked. Co-Authored-By: Claude Sonnet 4.6 --- .../archunit/JSpecifyAnnotationsCheck.groovy | 66 ------------------- 1 file changed, 66 deletions(-) diff --git a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy index 1b6cdafa6..d0881fbb7 100644 --- a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy +++ b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy @@ -11,53 +11,7 @@ import spock.lang.Specification class JSpecifyAnnotationsCheck extends Specification { private static final Set JSPECIFY_EXEMPTION_LIST = [ - "graphql.analysis.QueryComplexityCalculator", - "graphql.analysis.QueryComplexityInfo", - "graphql.analysis.QueryDepthInfo", - "graphql.analysis.QueryReducer", - "graphql.analysis.QueryTransformer", - "graphql.analysis.QueryTraversalOptions", "graphql.analysis.QueryTraverser", - "graphql.analysis.QueryVisitor", - "graphql.analysis.QueryVisitorFieldArgumentEnvironment", - "graphql.analysis.QueryVisitorFieldArgumentInputValue", - "graphql.analysis.QueryVisitorFieldArgumentValueEnvironment", - "graphql.analysis.QueryVisitorFieldEnvironment", - "graphql.analysis.QueryVisitorFragmentDefinitionEnvironment", - "graphql.analysis.QueryVisitorFragmentSpreadEnvironment", - "graphql.analysis.QueryVisitorInlineFragmentEnvironment", - "graphql.analysis.QueryVisitorStub", - "graphql.analysis.values.ValueTraverser", - "graphql.execution.AbortExecutionException", - "graphql.execution.AsyncExecutionStrategy", - "graphql.execution.AsyncSerialExecutionStrategy", - "graphql.execution.CoercedVariables", - "graphql.execution.DataFetcherExceptionHandlerParameters", - "graphql.execution.DataFetcherExceptionHandlerResult", - "graphql.execution.DefaultValueUnboxer", - "graphql.execution.ExecutionContext", - "graphql.execution.ExecutionId", - "graphql.execution.ExecutionStepInfo", - "graphql.execution.ExecutionStrategyParameters", - "graphql.execution.FetchedValue", - "graphql.execution.FieldValueInfo", - "graphql.execution.InputMapDefinesTooManyFieldsException", - "graphql.execution.MergedSelectionSet", - "graphql.execution.MissingRootTypeException", - "graphql.execution.NonNullableValueCoercedAsNullException", - "graphql.execution.NormalizedVariables", - "graphql.execution.OneOfNullValueException", - "graphql.execution.OneOfTooManyKeysException", - "graphql.execution.ResultNodesInfo", - "graphql.execution.ResultPath", - "graphql.execution.SimpleDataFetcherExceptionHandler", - "graphql.execution.SubscriptionExecutionStrategy", - "graphql.execution.UnknownOperationException", - "graphql.execution.UnresolvedTypeException", - "graphql.execution.conditional.ConditionalNodeDecision", - "graphql.execution.directives.QueryAppliedDirective", - "graphql.execution.directives.QueryAppliedDirectiveArgument", - "graphql.execution.directives.QueryDirectives", "graphql.execution.incremental.DeferredExecution", "graphql.execution.instrumentation.ChainedInstrumentation", "graphql.execution.instrumentation.DocumentAndVariables", @@ -68,26 +22,6 @@ class JSpecifyAnnotationsCheck extends Specification { "graphql.execution.instrumentation.SimplePerformantInstrumentation", "graphql.execution.instrumentation.fieldvalidation.FieldAndArguments", "graphql.execution.instrumentation.fieldvalidation.FieldValidationEnvironment", - "graphql.execution.instrumentation.fieldvalidation.FieldValidationInstrumentation", - "graphql.execution.instrumentation.fieldvalidation.SimpleFieldValidation", - "graphql.execution.instrumentation.parameters.InstrumentationCreateStateParameters", - "graphql.execution.instrumentation.parameters.InstrumentationExecuteOperationParameters", - "graphql.execution.instrumentation.parameters.InstrumentationExecutionParameters", - "graphql.execution.instrumentation.parameters.InstrumentationExecutionStrategyParameters", - "graphql.execution.instrumentation.parameters.InstrumentationFieldCompleteParameters", - "graphql.execution.instrumentation.parameters.InstrumentationFieldFetchParameters", - "graphql.execution.instrumentation.parameters.InstrumentationFieldParameters", - "graphql.execution.instrumentation.parameters.InstrumentationValidationParameters", - "graphql.execution.instrumentation.tracing.TracingInstrumentation", - "graphql.execution.instrumentation.tracing.TracingSupport", - "graphql.execution.preparsed.PreparsedDocumentEntry", - "graphql.execution.preparsed.persisted.ApolloPersistedQuerySupport", - "graphql.execution.preparsed.persisted.InMemoryPersistedQueryCache", - "graphql.execution.preparsed.persisted.PersistedQueryCacheMiss", - "graphql.execution.preparsed.persisted.PersistedQueryIdInvalid", - "graphql.execution.preparsed.persisted.PersistedQueryNotFound", - "graphql.execution.reactive.DelegatingSubscription", - "graphql.execution.reactive.SubscriptionPublisher", "graphql.extensions.ExtensionsBuilder", "graphql.incremental.DeferPayload", "graphql.incremental.DelayedIncrementalPartialResult", From bb25aed492b2f069d73a00d6ba9d9c54d5eb7cd0 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sun, 1 Mar 2026 16:18:22 +1100 Subject: [PATCH 71/71] Clarify jspecify-annotate prompt: public API only, fix exemption cleanup - Explicitly state that @Internal classes must not be annotated - Tighten exemption list cleanup instruction to remove only the annotated class Co-Authored-By: Claude Sonnet 4.6 --- .claude/commands/jspecify-annotate.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.claude/commands/jspecify-annotate.md b/.claude/commands/jspecify-annotate.md index 7083a6b3d..e1df47e63 100644 --- a/.claude/commands/jspecify-annotate.md +++ b/.claude/commands/jspecify-annotate.md @@ -1,7 +1,11 @@ -The task is to annotate public API classes (marked with `@PublicAPI`) with JSpecify nullability annotations. +The task is to annotate public API classes (marked with `@PublicApi` or `@PublicSpi`) with JSpecify nullability annotations. Note that JSpecify is already used in this repository so it's already imported. +## Scope: Public API only + +Only annotate classes marked `@PublicApi` or `@PublicSpi`. Do **not** add JSpecify annotations to `@Internal` classes — these are implementation details and are intentionally left unannotated. + If you see a builder static class, you can label it `@NullUnmarked` and not need to do anymore for this static class in terms of annotations. Analyze this Java class and add JSpecify annotations based on: @@ -29,9 +33,11 @@ If you find NullAway errors, try and make the smallest possible change to fix th Do not make spacing or formatting changes. Avoid adjusting whitespace, line breaks, or other formatting when editing code. These changes make diffs messy and harder to review. Only make the minimal changes necessary to accomplish the task. ## Cleaning up -Finally, can you remove this class from the JSpecifyAnnotationsCheck as an exemption +Finally, remove this class from the exemption list in `JSpecifyAnnotationsCheck.groovy`. + +The exemption list contains fully-qualified class names. Remove **only** the class you just annotated — do not remove entries for `@Internal` classes or any other class you did not annotate. -You do not need to run the JSpecifyAnnotationsCheck. Removing the completed class is enough. +You do not need to run the JSpecifyAnnotationsCheck. Removing the completed class from the list is enough. Remember to delete all unused imports when you're done from the class you've just annotated.