Skip to content

Commit a6cc631

Browse files
dondonzclaudeandimarek
authored
JSpecify big wave 3 (#4274)
* Add JSpecify agent team orchestrator prompt https://claude.ai/code/session_01FG3V2VvjSSbUVcjn9FX4yx * Move to .claude folder * Add JSpecify annotations to QueryComplexityCalculator * Add JSpecify annotations to AbortExecutionException * Add JSpecify annotations to ConditionalNodeDecision * Add JSpecify annotations to AsyncExecutionStrategy * Add JSpecify annotations to QueryComplexityInfo * Add JSpecify annotations to AsyncSerialExecutionStrategy * Add JSpecify annotations to QueryDepthInfo * Add JSpecify annotations to CoercedVariables * Add JSpecify annotations to QueryReducer * Add JSpecify annotations to QueryAppliedDirective * Add JSpecify annotations to DataFetcherExceptionHandlerParameters * Add JSpecify annotations to DataFetcherExceptionHandlerResult * Add JSpecify annotations to QueryTransformer * Add JSpecify annotations to DefaultValueUnboxer * Add JSpecify annotations to QueryAppliedDirectiveArgument * Add JSpecify annotations to QueryTraversalOptions * Add JSpecify annotations to QueryVisitor * Add JSpecify annotations to ExecutionContext * Add JSpecify annotations to ExecutionId * Add JSpecify annotations to QueryDirectives * Add JSpecify annotations to QueryVisitorFieldArgumentEnvironment * Add JSpecify annotations to QueryVisitorFieldArgumentInputValue * Add JSpecify annotations to FieldValidationInstrumentation * Add JSpecify annotations to QueryVisitorFieldArgumentValueEnvironment * Add JSpecify annotations to SimpleFieldValidation * Add JSpecify annotations to InstrumentationCreateStateParameters * Add JSpecify annotations to ExecutionStepInfo * Add JSpecify annotations to QueryVisitorFieldEnvironment * Add JSpecify annotations to InstrumentationExecuteOperationParameters * Add JSpecify annotations to QueryVisitorFragmentDefinitionEnvironment * Add JSpecify annotations to QueryVisitorFragmentSpreadEnvironment * Add JSpecify annotations to QueryVisitorInlineFragmentEnvironment * Add JSpecify annotations to QueryVisitorStub * Add JSpecify annotations to InstrumentationExecutionParameters * Add JSpecify annotations to InstrumentationExecutionStrategyParameters * Add JSpecify annotations to ExecutionStrategyParameters * Add JSpecify annotations to InstrumentationFieldCompleteParameters * Add JSpecify annotations to FetchedValue * Add JSpecify annotations to InstrumentationFieldFetchParameters * Add JSpecify annotations to InstrumentationFieldParameters * Add JSpecify annotations to FieldValueInfo * Add JSpecify annotations to InstrumentationValidationParameters * Add JSpecify annotations to InputMapDefinesTooManyFieldsException * Add JSpecify annotations to TracingInstrumentation * Add JSpecify annotations to ValueTraverser * Add JSpecify annotations to MergedSelectionSet * Add JSpecify annotations to MissingRootTypeException * Add JSpecify annotations to TracingSupport * Add JSpecify annotations to NonNullableValueCoercedAsNullException * Add JSpecify annotations to NormalizedVariables * Add JSpecify annotations to PreparsedDocumentEntry * Add JSpecify annotations to OneOfNullValueException * Add JSpecify annotations to ApolloPersistedQuerySupport * Add JSpecify annotations to OneOfTooManyKeysException * Add JSpecify annotations to InMemoryPersistedQueryCache * Add JSpecify annotations to ResultNodesInfo * Add JSpecify annotations to PersistedQueryCacheMiss * Add JSpecify annotations to PersistedQueryIdInvalid * Add JSpecify annotations to PersistedQueryNotFound * Add JSpecify annotations to ResultPath * Add JSpecify annotations to DelegatingSubscription * Add JSpecify annotations to SimpleDataFetcherExceptionHandler * Add JSpecify annotations to SubscriptionPublisher * Add JSpecify annotations to SubscriptionExecutionStrategy * Add JSpecify annotations to UnknownOperationException * Add JSpecify annotations to UnresolvedTypeException * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * 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 <noreply@anthropic.com> * Address comments * Adjust for new operation directives * Fix failing tests: update PreparsedDocumentEntry test and remove annotated classes from exemption list - Update PreparsedDocumentEntryTest to expect empty list instead of null for errors - Remove 10 classes from JSpecify exemption list that are already annotated Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix NullAway error: assert document non-null at assignment in GraphQL.parseAndValidate Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Andreas Marek <andimarek@fastmail.fm>
1 parent d26e4d6 commit a6cc631

73 files changed

Lines changed: 332 additions & 212 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/main/java/graphql/ExceptionWhileDataFetching.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public class ExceptionWhileDataFetching implements GraphQLError {
2727
private final List<SourceLocation> locations;
2828
private final @Nullable Map<String, Object> extensions;
2929

30-
public ExceptionWhileDataFetching(ResultPath path, Throwable exception, SourceLocation sourceLocation) {
30+
public ExceptionWhileDataFetching(ResultPath path, Throwable exception, @Nullable SourceLocation sourceLocation) {
3131
this.path = assertNotNull(path).toList();
3232
this.exception = assertNotNull(exception);
3333
this.locations = Collections.singletonList(sourceLocation);

src/main/java/graphql/GraphQL.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,7 @@ private CompletableFuture<ExecutionResult> parseValidateAndExecute(ExecutionInpu
550550
return CompletableFuture.completedFuture(new ExecutionResultImpl(preparsedDocumentEntry.getErrors()));
551551
}
552552
try {
553-
return execute(Assert.assertNotNull(executionInputRef.get()), preparsedDocumentEntry.getDocument(), graphQLSchema, instrumentationState, engineRunningState, profiler);
553+
return execute(Assert.assertNotNull(executionInputRef.get()), assertNotNull(preparsedDocumentEntry.getDocument(), "document must not be null"), graphQLSchema, instrumentationState, engineRunningState, profiler);
554554
} catch (AbortExecutionException e) {
555555
return CompletableFuture.completedFuture(e.toExecutionResult());
556556
}
@@ -565,14 +565,14 @@ private PreparsedDocumentEntry parseAndValidate(AtomicReference<ExecutionInput>
565565
if (parseResult.isFailure()) {
566566
return new PreparsedDocumentEntry(assertNotNull(parseResult.getSyntaxException(), "Parse result syntax exception cannot be null when failed").toInvalidSyntaxError());
567567
} else {
568-
final Document document = parseResult.getDocument();
568+
final Document document = assertNotNull(parseResult.getDocument(), "Document cannot be null when parse succeeded");
569569
// they may have changed the document and the variables via instrumentation so update the reference to it
570570
executionInput = executionInput.transform(builder -> builder.variables(parseResult.getVariables()));
571571
executionInputRef.set(executionInput);
572572

573573
final List<ValidationError> errors;
574574
try {
575-
errors = validate(executionInput, assertNotNull(document, "Document cannot be null when parse succeeded"), graphQLSchema, instrumentationState);
575+
errors = validate(executionInput, document, graphQLSchema, instrumentationState);
576576
} catch (GoodFaithIntrospectionExceeded e) {
577577
return new PreparsedDocumentEntry(document, List.of(e.toBadFaithError()));
578578
}

src/main/java/graphql/UnresolvedTypeError.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ private String mkMessage(ResultPath path, UnresolvedTypeException exception, Exe
3232
return format("Can't resolve '%s'. Abstract type '%s' must resolve to an Object type at runtime for field '%s.%s'. %s",
3333
path,
3434
exception.getInterfaceOrUnionType().getName(),
35-
simplePrint(info.getParent().getUnwrappedNonNullType()),
36-
info.getFieldDefinition().getName(),
35+
simplePrint(assertNotNull(info.getParent(), "executionStepInfo parent must not be null").getUnwrappedNonNullType()),
36+
assertNotNull(info.getFieldDefinition(), "fieldDefinition must not be null").getName(),
3737
exception.getMessage());
3838
}
3939

src/main/java/graphql/analysis/MaxQueryDepthInstrumentation.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import graphql.execution.instrumentation.SimplePerformantInstrumentation;
1010
import graphql.execution.instrumentation.parameters.InstrumentationExecuteOperationParameters;
1111
import org.jspecify.annotations.NullMarked;
12+
import org.jspecify.annotations.Nullable;
1213

1314
import java.util.function.Function;
1415

@@ -84,7 +85,7 @@ QueryTraverser newQueryTraverser(ExecutionContext executionContext) {
8485
.build();
8586
}
8687

87-
private int getPathLength(QueryVisitorFieldEnvironment path) {
88+
private int getPathLength(@Nullable QueryVisitorFieldEnvironment path) {
8889
int length = 1;
8990
while (path != null) {
9091
path = path.getParentEnvironment();

src/main/java/graphql/analysis/QueryComplexityCalculator.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
import graphql.execution.CoercedVariables;
55
import graphql.language.Document;
66
import graphql.schema.GraphQLSchema;
7+
import org.jspecify.annotations.NullMarked;
8+
import org.jspecify.annotations.NullUnmarked;
9+
import org.jspecify.annotations.Nullable;
710

811
import java.util.LinkedHashMap;
912
import java.util.Map;
@@ -16,12 +19,13 @@
1619
* into it.
1720
*/
1821
@PublicApi
22+
@NullMarked
1923
public class QueryComplexityCalculator {
2024

2125
private final FieldComplexityCalculator fieldComplexityCalculator;
2226
private final GraphQLSchema schema;
2327
private final Document document;
24-
private final String operationName;
28+
private final @Nullable String operationName;
2529
private final CoercedVariables variables;
2630

2731
public QueryComplexityCalculator(Builder builder) {
@@ -95,6 +99,7 @@ public static Builder newCalculator() {
9599
return new Builder();
96100
}
97101

102+
@NullUnmarked
98103
public static class Builder {
99104
private FieldComplexityCalculator fieldComplexityCalculator;
100105
private GraphQLSchema schema;

src/main/java/graphql/analysis/QueryComplexityInfo.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,20 @@
33
import graphql.PublicApi;
44
import graphql.execution.instrumentation.parameters.InstrumentationExecuteOperationParameters;
55
import graphql.execution.instrumentation.parameters.InstrumentationValidationParameters;
6+
import org.jspecify.annotations.NullMarked;
7+
import org.jspecify.annotations.Nullable;
68
import org.jspecify.annotations.NullUnmarked;
79

810
/**
911
* The query complexity info.
1012
*/
1113
@PublicApi
14+
@NullMarked
1215
public class QueryComplexityInfo {
1316

1417
private final int complexity;
15-
private final InstrumentationValidationParameters instrumentationValidationParameters;
16-
private final InstrumentationExecuteOperationParameters instrumentationExecuteOperationParameters;
18+
private final @Nullable InstrumentationValidationParameters instrumentationValidationParameters;
19+
private final @Nullable InstrumentationExecuteOperationParameters instrumentationExecuteOperationParameters;
1720

1821
private QueryComplexityInfo(Builder builder) {
1922
this.complexity = builder.complexity;
@@ -35,7 +38,7 @@ public int getComplexity() {
3538
*
3639
* @return the instrumentation validation parameters.
3740
*/
38-
public InstrumentationValidationParameters getInstrumentationValidationParameters() {
41+
public @Nullable InstrumentationValidationParameters getInstrumentationValidationParameters() {
3942
return instrumentationValidationParameters;
4043
}
4144

@@ -44,7 +47,7 @@ public InstrumentationValidationParameters getInstrumentationValidationParameter
4447
*
4548
* @return the instrumentation execute operation parameters.
4649
*/
47-
public InstrumentationExecuteOperationParameters getInstrumentationExecuteOperationParameters() {
50+
public @Nullable InstrumentationExecuteOperationParameters getInstrumentationExecuteOperationParameters() {
4851
return instrumentationExecuteOperationParameters;
4952
}
5053

src/main/java/graphql/analysis/QueryDepthInfo.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package graphql.analysis;
22

33
import graphql.PublicApi;
4+
import org.jspecify.annotations.NullMarked;
45
import org.jspecify.annotations.NullUnmarked;
56

67
/**
78
* The query depth info.
89
*/
910
@PublicApi
11+
@NullMarked
1012
public class QueryDepthInfo {
1113

1214
private final int depth;

src/main/java/graphql/analysis/QueryReducer.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package graphql.analysis;
22

33
import graphql.PublicApi;
4+
import org.jspecify.annotations.NullMarked;
45

56
/**
67
* Used by {@link QueryTraverser} to reduce the fields of a Document (or part of it) to a single value.
@@ -10,6 +11,7 @@
1011
* See {@link QueryTraverser#reducePostOrder(QueryReducer, Object)} and {@link QueryTraverser#reducePreOrder(QueryReducer, Object)}
1112
*/
1213
@PublicApi
14+
@NullMarked
1315
@FunctionalInterface
1416
public interface QueryReducer<T> {
1517

src/main/java/graphql/analysis/QueryTransformer.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
import java.util.LinkedHashMap;
1515
import java.util.Map;
16+
import org.jspecify.annotations.NullMarked;
1617
import org.jspecify.annotations.NullUnmarked;
1718

1819
import static graphql.Assert.assertNotNull;
@@ -31,6 +32,7 @@
3132
* visitField calls.
3233
*/
3334
@PublicApi
35+
@NullMarked
3436
public class QueryTransformer {
3537

3638
private final Node root;

src/main/java/graphql/analysis/QueryTraversalOptions.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package graphql.analysis;
22

33
import graphql.PublicApi;
4+
import org.jspecify.annotations.NullMarked;
45

56
/**
67
* This options object controls how {@link QueryTraverser} works
78
*/
89
@PublicApi
10+
@NullMarked
911
public class QueryTraversalOptions {
1012

1113
private final boolean coerceFieldArguments;

0 commit comments

Comments
 (0)