Skip to content

Commit e0c5f0b

Browse files
Add JSpecify @NullMarked annotations to ValidationContext and OperationValidator
ValidationContext: - Add @NullMarked at class level - Add @nullable to methods that can return null based on traversal state: getFragment, getParentType, getInputType, getDefaultValue, getFieldDef, getDirective, getArgument, getOutputType, getQueryPath OperationValidator: - Add @NullMarked at class level - Add @nullable to methods that can return null: getQueryPath, requireSameNameAndArguments, findArgumentByName, requireSameOutputTypeShape - Add @nullable to parameters that can be null: addError (SourceLocation), mkNotSameTypeError (typeA, typeB), overlappingFieldsImpl, overlappingFields_collectFields, overlappingFields_collectFieldsForInlineFragment, overlappingFields_collectFieldsForField, sameType, sameArguments - Add @nullable to fields that can be null: variableDefinitionMap, FieldAndType.graphQLType Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 72b2828 commit e0c5f0b

2 files changed

Lines changed: 31 additions & 26 deletions

File tree

src/main/java/graphql/validation/OperationValidator.java

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@
5757
import graphql.schema.GraphQLUnmodifiedType;
5858
import graphql.schema.InputValueWithState;
5959
import graphql.util.StringKit;
60+
import org.jspecify.annotations.NullMarked;
61+
import org.jspecify.annotations.Nullable;
6062

6163
import java.util.ArrayList;
6264
import java.util.Collection;
@@ -262,6 +264,7 @@
262264
* @see OperationValidationRule
263265
*/
264266
@Internal
267+
@NullMarked
265268
@SuppressWarnings("rawtypes")
266269
public class OperationValidator implements DocumentVisitor {
267270

@@ -297,7 +300,7 @@ public class OperationValidator implements DocumentVisitor {
297300

298301
// --- State: VariableTypesMatch ---
299302
private final VariablesTypesMatcher variablesTypesMatcher = new VariablesTypesMatcher();
300-
private Map<String, VariableDefinition> variableDefinitionMap;
303+
private @Nullable Map<String, VariableDefinition> variableDefinitionMap;
301304

302305
// --- State: OverlappingFieldsCanBeMerged ---
303306
private final Set<Set<FieldAndType>> sameResponseShapeChecked = new LinkedHashSet<>();
@@ -427,7 +430,7 @@ private void addError(ValidationErrorType validationErrorType, Collection<? exte
427430
.description(description));
428431
}
429432

430-
private void addError(ValidationErrorType validationErrorType, SourceLocation location, String description) {
433+
private void addError(ValidationErrorType validationErrorType, @Nullable SourceLocation location, String description) {
431434
addError(newValidationError()
432435
.validationErrorType(validationErrorType)
433436
.sourceLocation(location)
@@ -438,7 +441,7 @@ private void addError(ValidationError.Builder validationError) {
438441
errorCollector.addError(validationError.queryPath(getQueryPath()).build());
439442
}
440443

441-
private List<String> getQueryPath() {
444+
private @Nullable List<String> getQueryPath() {
442445
return validationContext.getQueryPath();
443446
}
444447

@@ -985,7 +988,7 @@ private void validateOverlappingFieldsCanBeMerged(OperationDefinition operationD
985988
overlappingFieldsImpl(operationDefinition.getSelectionSet(), validationContext.getOutputType());
986989
}
987990

988-
private void overlappingFieldsImpl(SelectionSet selectionSet, GraphQLOutputType graphQLOutputType) {
991+
private void overlappingFieldsImpl(SelectionSet selectionSet, @Nullable GraphQLOutputType graphQLOutputType) {
989992
Map<String, Set<FieldAndType>> fieldMap = new LinkedHashMap<>();
990993
Set<String> visitedFragments = new LinkedHashSet<>();
991994
overlappingFields_collectFields(fieldMap, selectionSet, graphQLOutputType, visitedFragments);
@@ -999,7 +1002,7 @@ private void overlappingFieldsImpl(SelectionSet selectionSet, GraphQLOutputType
9991002
}
10001003
}
10011004

1002-
private void overlappingFields_collectFields(Map<String, Set<FieldAndType>> fieldMap, SelectionSet selectionSet, GraphQLType parentType, Set<String> visitedFragments) {
1005+
private void overlappingFields_collectFields(Map<String, Set<FieldAndType>> fieldMap, SelectionSet selectionSet, @Nullable GraphQLType parentType, Set<String> visitedFragments) {
10031006
for (Selection selection : selectionSet.getSelections()) {
10041007
if (selection instanceof Field) {
10051008
overlappingFields_collectFieldsForField(fieldMap, parentType, (Field) selection);
@@ -1020,7 +1023,7 @@ private void overlappingFields_collectFieldsForFragmentSpread(Map<String, Set<Fi
10201023
overlappingFields_collectFields(fieldMap, fragment.getSelectionSet(), graphQLType, visitedFragments);
10211024
}
10221025

1023-
private void overlappingFields_collectFieldsForInlineFragment(Map<String, Set<FieldAndType>> fieldMap, Set<String> visitedFragments, GraphQLType parentType, InlineFragment inlineFragment) {
1026+
private void overlappingFields_collectFieldsForInlineFragment(Map<String, Set<FieldAndType>> fieldMap, Set<String> visitedFragments, @Nullable GraphQLType parentType, InlineFragment inlineFragment) {
10241027
GraphQLType graphQLType;
10251028
if (inlineFragment.getTypeCondition() == null) {
10261029
graphQLType = parentType;
@@ -1030,7 +1033,7 @@ private void overlappingFields_collectFieldsForInlineFragment(Map<String, Set<Fi
10301033
overlappingFields_collectFields(fieldMap, inlineFragment.getSelectionSet(), graphQLType, visitedFragments);
10311034
}
10321035

1033-
private void overlappingFields_collectFieldsForField(Map<String, Set<FieldAndType>> fieldMap, GraphQLType parentType, Field field) {
1036+
private void overlappingFields_collectFieldsForField(Map<String, Set<FieldAndType>> fieldMap, @Nullable GraphQLType parentType, Field field) {
10341037
String responseName = field.getResultKey();
10351038
if (!fieldMap.containsKey(responseName)) {
10361039
fieldMap.put(responseName, new LinkedHashSet<>());
@@ -1120,7 +1123,7 @@ private boolean isInterfaceOrUnion(GraphQLType type) {
11201123
return type instanceof GraphQLInterfaceType || type instanceof GraphQLUnionType;
11211124
}
11221125

1123-
private Conflict requireSameNameAndArguments(ImmutableList<String> path, Set<FieldAndType> fieldAndTypes) {
1126+
private @Nullable Conflict requireSameNameAndArguments(ImmutableList<String> path, Set<FieldAndType> fieldAndTypes) {
11241127
if (fieldAndTypes.size() <= 1) {
11251128
return null;
11261129
}
@@ -1151,8 +1154,8 @@ private String pathToString(ImmutableList<String> path) {
11511154
return String.join("/", path);
11521155
}
11531156

1154-
private boolean sameArguments(List<Argument> arguments1, List<Argument> arguments2) {
1155-
if (arguments1.size() != arguments2.size()) {
1157+
private boolean sameArguments(List<Argument> arguments1, @Nullable List<Argument> arguments2) {
1158+
if (arguments2 == null || arguments1.size() != arguments2.size()) {
11561159
return false;
11571160
}
11581161
for (Argument argument : arguments1) {
@@ -1167,7 +1170,7 @@ private boolean sameArguments(List<Argument> arguments1, List<Argument> argument
11671170
return true;
11681171
}
11691172

1170-
private Argument findArgumentByName(String name, List<Argument> arguments) {
1173+
private @Nullable Argument findArgumentByName(String name, List<Argument> arguments) {
11711174
for (Argument argument : arguments) {
11721175
if (argument.getName().equals(name)) {
11731176
return argument;
@@ -1176,7 +1179,7 @@ private Argument findArgumentByName(String name, List<Argument> arguments) {
11761179
return null;
11771180
}
11781181

1179-
private Conflict requireSameOutputTypeShape(ImmutableList<String> path, Set<FieldAndType> fieldAndTypes) {
1182+
private @Nullable Conflict requireSameOutputTypeShape(ImmutableList<String> path, Set<FieldAndType> fieldAndTypes) {
11801183
if (fieldAndTypes.size() <= 1) {
11811184
return null;
11821185
}
@@ -1223,14 +1226,14 @@ private Conflict requireSameOutputTypeShape(ImmutableList<String> path, Set<Fiel
12231226
return null;
12241227
}
12251228

1226-
private Conflict mkNotSameTypeError(ImmutableList<String> path, List<Field> fields, GraphQLType typeA, GraphQLType typeB) {
1229+
private Conflict mkNotSameTypeError(ImmutableList<String> path, List<Field> fields, @Nullable GraphQLType typeA, @Nullable GraphQLType typeB) {
12271230
String name1 = typeA != null ? simplePrint(typeA) : "null";
12281231
String name2 = typeB != null ? simplePrint(typeB) : "null";
12291232
String reason = i18n(FieldsConflict, "OverlappingFieldsCanBeMerged.differentReturnTypes", pathToString(path), name1, name2);
12301233
return new Conflict(reason, fields);
12311234
}
12321235

1233-
private boolean sameType(GraphQLType type1, GraphQLType type2) {
1236+
private boolean sameType(@Nullable GraphQLType type1, @Nullable GraphQLType type2) {
12341237
if (type1 == null || type2 == null) {
12351238
return true;
12361239
}
@@ -1239,10 +1242,10 @@ private boolean sameType(GraphQLType type1, GraphQLType type2) {
12391242

12401243
private static class FieldAndType {
12411244
final Field field;
1242-
final GraphQLType graphQLType;
1245+
final @Nullable GraphQLType graphQLType;
12431246
final GraphQLType parentType;
12441247

1245-
public FieldAndType(Field field, GraphQLType graphQLType, GraphQLType parentType) {
1248+
public FieldAndType(Field field, @Nullable GraphQLType graphQLType, GraphQLType parentType) {
12461249
this.field = field;
12471250
this.graphQLType = graphQLType;
12481251
this.parentType = parentType;

src/main/java/graphql/validation/ValidationContext.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package graphql.validation;
22

3-
43
import graphql.GraphQLContext;
54
import graphql.Internal;
65
import graphql.i18n.I18n;
@@ -15,13 +14,16 @@
1514
import graphql.schema.GraphQLOutputType;
1615
import graphql.schema.GraphQLSchema;
1716
import graphql.schema.InputValueWithState;
17+
import org.jspecify.annotations.NullMarked;
18+
import org.jspecify.annotations.Nullable;
1819

1920
import java.util.LinkedHashMap;
2021
import java.util.List;
2122
import java.util.Locale;
2223
import java.util.Map;
2324

2425
@Internal
26+
@NullMarked
2527
public class ValidationContext {
2628

2729
private final GraphQLSchema schema;
@@ -63,39 +65,39 @@ public Document getDocument() {
6365
return document;
6466
}
6567

66-
public FragmentDefinition getFragment(String name) {
68+
public @Nullable FragmentDefinition getFragment(String name) {
6769
return fragmentDefinitionMap.get(name);
6870
}
6971

70-
public GraphQLCompositeType getParentType() {
72+
public @Nullable GraphQLCompositeType getParentType() {
7173
return traversalContext.getParentType();
7274
}
7375

74-
public GraphQLInputType getInputType() {
76+
public @Nullable GraphQLInputType getInputType() {
7577
return traversalContext.getInputType();
7678
}
7779

78-
public InputValueWithState getDefaultValue() {
80+
public @Nullable InputValueWithState getDefaultValue() {
7981
return traversalContext.getDefaultValue();
8082
}
8183

82-
public GraphQLFieldDefinition getFieldDef() {
84+
public @Nullable GraphQLFieldDefinition getFieldDef() {
8385
return traversalContext.getFieldDef();
8486
}
8587

86-
public GraphQLDirective getDirective() {
88+
public @Nullable GraphQLDirective getDirective() {
8789
return traversalContext.getDirective();
8890
}
8991

90-
public GraphQLArgument getArgument() {
92+
public @Nullable GraphQLArgument getArgument() {
9193
return traversalContext.getArgument();
9294
}
9395

94-
public GraphQLOutputType getOutputType() {
96+
public @Nullable GraphQLOutputType getOutputType() {
9597
return traversalContext.getOutputType();
9698
}
9799

98-
public List<String> getQueryPath() {
100+
public @Nullable List<String> getQueryPath() {
99101
return traversalContext.getQueryPath();
100102
}
101103

0 commit comments

Comments
 (0)