From 1b01d2be7b93674fb7d7057f8752aa5c2acaeb70 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Thu, 21 Aug 2025 19:23:43 +1000 Subject: [PATCH 01/16] Annotate GraphQLAppliedDirective --- .../java/graphql/schema/GraphQLAppliedDirective.java | 9 +++++++-- .../graphql/archunit/JSpecifyAnnotationsCheck.groovy | 1 - 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/graphql/schema/GraphQLAppliedDirective.java b/src/main/java/graphql/schema/GraphQLAppliedDirective.java index ba73f99701..54104e7f7b 100644 --- a/src/main/java/graphql/schema/GraphQLAppliedDirective.java +++ b/src/main/java/graphql/schema/GraphQLAppliedDirective.java @@ -6,6 +6,9 @@ import graphql.language.Directive; import graphql.util.TraversalControl; import graphql.util.TraverserContext; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.NullUnmarked; +import org.jspecify.annotations.Nullable; import java.util.LinkedHashMap; import java.util.List; @@ -31,6 +34,7 @@ * See https://graphql.org/learn/queries/#directives for more details on the concept. */ @PublicApi +@NullMarked public class GraphQLAppliedDirective implements GraphQLNamedSchemaElement { private final String name; @@ -53,7 +57,7 @@ public String getName() { } @Override - public String getDescription() { + public @Nullable String getDescription() { return null; } @@ -61,7 +65,7 @@ public List getArguments() { return arguments; } - public GraphQLAppliedDirectiveArgument getArgument(String name) { + public @Nullable GraphQLAppliedDirectiveArgument getArgument(String name) { for (GraphQLAppliedDirectiveArgument argument : arguments) { if (argument.getName().equals(name)) { return argument; @@ -152,6 +156,7 @@ public static Builder newDirective(GraphQLAppliedDirective existing) { return new Builder(existing); } + @NullUnmarked public static class Builder extends GraphqlTypeBuilder { private final Map arguments = new LinkedHashMap<>(); diff --git a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy index 95dc0cc435..791c68af49 100644 --- a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy +++ b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy @@ -227,7 +227,6 @@ class JSpecifyAnnotationsCheck extends Specification { "graphql.schema.DefaultGraphqlTypeComparatorRegistry", "graphql.schema.DelegatingDataFetchingEnvironment", "graphql.schema.FieldCoordinates", - "graphql.schema.GraphQLAppliedDirective", "graphql.schema.GraphQLAppliedDirectiveArgument", "graphql.schema.GraphQLArgument", "graphql.schema.GraphQLCodeRegistry", From 8684b480c4d26354f5018b256679d72017fcf04c Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Thu, 21 Aug 2025 19:51:56 +1000 Subject: [PATCH 02/16] Add GraphQLSchema annotation --- .../java/graphql/schema/GraphQLSchema.java | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/main/java/graphql/schema/GraphQLSchema.java b/src/main/java/graphql/schema/GraphQLSchema.java index 5b480810c9..ed7912c802 100644 --- a/src/main/java/graphql/schema/GraphQLSchema.java +++ b/src/main/java/graphql/schema/GraphQLSchema.java @@ -18,7 +18,8 @@ import graphql.schema.validation.InvalidSchemaException; import graphql.schema.validation.SchemaValidationError; import graphql.schema.validation.SchemaValidator; -import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.NullUnmarked; import org.jspecify.annotations.Nullable; import java.util.ArrayList; @@ -46,6 +47,7 @@ * See https://graphql.org/learn/schema/#type-language for more details */ @PublicApi +@NullMarked public class GraphQLSchema { private final GraphQLObjectType queryType; @@ -63,7 +65,7 @@ public class GraphQLSchema { private final SchemaDefinition definition; private final ImmutableList extensionDefinitions; private final String description; - private final GraphQLCodeRegistry codeRegistry; + private final @Nullable GraphQLCodeRegistry codeRegistry; private final ImmutableMap typeMap; private final ImmutableMap> interfaceNameToObjectTypes; @@ -190,7 +192,7 @@ private static ImmutableMap> buildInterfacesToObje return map.build(); } - public GraphQLCodeRegistry getCodeRegistry() { + public @Nullable GraphQLCodeRegistry getCodeRegistry() { return codeRegistry; } @@ -230,7 +232,7 @@ public Set getAdditionalTypes() { * * @return the type */ - public @Nullable GraphQLType getType(@NonNull String typeName) { + public @Nullable GraphQLType getType(String typeName) { return typeMap.get(typeName); } @@ -262,7 +264,7 @@ public List getTypes(Collection typeNames) { * * @return the type cast to the target type. */ - public T getTypeAs(String typeName) { + public @Nullable T getTypeAs(String typeName) { //noinspection unchecked return (T) typeMap.get(typeName); } @@ -287,7 +289,7 @@ public boolean containsType(String typeName) { * * @throws graphql.GraphQLException if the type is NOT an object type */ - public GraphQLObjectType getObjectType(String typeName) { + public @Nullable GraphQLObjectType getObjectType(String typeName) { GraphQLType graphQLType = typeMap.get(typeName); if (graphQLType != null) { assertTrue(graphQLType instanceof GraphQLObjectType, @@ -304,7 +306,7 @@ public GraphQLObjectType getObjectType(String typeName) { * * @return the field or null if it does not exist */ - public GraphQLFieldDefinition getFieldDefinition(FieldCoordinates fieldCoordinates) { + public @Nullable GraphQLFieldDefinition getFieldDefinition(FieldCoordinates fieldCoordinates) { String fieldName = fieldCoordinates.getFieldName(); if (fieldCoordinates.isSystemCoordinates()) { if (fieldName.equals(this.getIntrospectionSchemaFieldDefinition().getName())) { @@ -365,7 +367,7 @@ public List getAllElementsAsList() { * * @return list of types implementing provided interface */ - public List getImplementations(GraphQLInterfaceType type) { + public @Nullable List getImplementations(GraphQLInterfaceType type) { return interfaceNameToObjectTypes.getOrDefault(type.getName(), emptyList()); } @@ -642,6 +644,7 @@ public static Builder newSchema(GraphQLSchema existingSchema) { .description(existingSchema.getDescription()); } + @NullUnmarked public static class BuilderWithoutTypes { private GraphQLCodeRegistry codeRegistry; private String description; @@ -672,6 +675,7 @@ public GraphQLSchema build() { } } + @NullUnmarked public static class Builder { private GraphQLObjectType queryType; private GraphQLObjectType mutationType; @@ -752,7 +756,6 @@ public Builder clearDirectives() { return this; } - public Builder withSchemaDirectives(GraphQLDirective... directives) { for (GraphQLDirective directive : directives) { withSchemaDirective(directive); From 0cdc8de9217781de563ecd46c3fff5e2adae5bb2 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Thu, 21 Aug 2025 19:52:07 +1000 Subject: [PATCH 03/16] Remove exemption --- src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy index 791c68af49..1e4430cb84 100644 --- a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy +++ b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy @@ -256,7 +256,6 @@ class JSpecifyAnnotationsCheck extends Specification { "graphql.schema.GraphQLObjectType", "graphql.schema.GraphQLOutputType", "graphql.schema.GraphQLScalarType", - "graphql.schema.GraphQLSchema", "graphql.schema.GraphQLSchemaElement", "graphql.schema.GraphQLType", "graphql.schema.GraphQLTypeReference", From 30d0abe5030860e27a7e15f3a1de7341d2cc12bc Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Thu, 21 Aug 2025 19:59:11 +1000 Subject: [PATCH 04/16] Annotate GraphQLType and GraphQLEnumType --- src/main/java/graphql/schema/GraphQLEnumType.java | 8 +++++--- src/main/java/graphql/schema/GraphQLType.java | 2 ++ .../graphql/archunit/JSpecifyAnnotationsCheck.groovy | 2 -- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/graphql/schema/GraphQLEnumType.java b/src/main/java/graphql/schema/GraphQLEnumType.java index 856907315d..0061d2b810 100644 --- a/src/main/java/graphql/schema/GraphQLEnumType.java +++ b/src/main/java/graphql/schema/GraphQLEnumType.java @@ -13,7 +13,8 @@ import graphql.util.FpKit; import graphql.util.TraversalControl; import graphql.util.TraverserContext; -import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.NullUnmarked; +import org.jspecify.annotations.Nullable; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -141,7 +142,7 @@ public List getValues() { return ImmutableList.copyOf(valueDefinitionMap.values()); } - public GraphQLEnumValueDefinition getValue(String name) { + public @Nullable GraphQLEnumValueDefinition getValue(String name) { return valueDefinitionMap.get(name); } @@ -150,7 +151,7 @@ private ImmutableMap buildMap(List assertShouldNeverHappen("Duplicated definition for field '%s' in type '%s'", fld1.getName(), this.name))); } - private Object getValueByName(@NonNull Object value, GraphQLContext graphQLContext, Locale locale) { + private Object getValueByName(Object value, GraphQLContext graphQLContext, Locale locale) { GraphQLEnumValueDefinition enumValueDefinition = valueDefinitionMap.get(value.toString()); if (enumValueDefinition != null) { return enumValueDefinition.getValue(); @@ -324,6 +325,7 @@ public static Builder newEnum(GraphQLEnumType existing) { return new Builder(existing); } + @NullUnmarked public static class Builder extends GraphqlDirectivesContainerTypeBuilder { private EnumTypeDefinition definition; diff --git a/src/main/java/graphql/schema/GraphQLType.java b/src/main/java/graphql/schema/GraphQLType.java index e47ed46a2e..a11099a86b 100644 --- a/src/main/java/graphql/schema/GraphQLType.java +++ b/src/main/java/graphql/schema/GraphQLType.java @@ -2,6 +2,7 @@ import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; /** * A type inside the GraphQLSchema. A type doesn't have to have name, e.g. {@link GraphQLList}. @@ -9,5 +10,6 @@ * See {@link GraphQLNamedType} for types with a name. */ @PublicApi +@NullMarked public interface GraphQLType extends GraphQLSchemaElement { } diff --git a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy index 1e4430cb84..da730aa5ca 100644 --- a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy +++ b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy @@ -233,7 +233,6 @@ class JSpecifyAnnotationsCheck extends Specification { "graphql.schema.GraphQLCompositeType", "graphql.schema.GraphQLDirective", "graphql.schema.GraphQLDirectiveContainer", - "graphql.schema.GraphQLEnumType", "graphql.schema.GraphQLEnumValueDefinition", "graphql.schema.GraphQLFieldDefinition", "graphql.schema.GraphQLFieldsContainer", @@ -257,7 +256,6 @@ class JSpecifyAnnotationsCheck extends Specification { "graphql.schema.GraphQLOutputType", "graphql.schema.GraphQLScalarType", "graphql.schema.GraphQLSchemaElement", - "graphql.schema.GraphQLType", "graphql.schema.GraphQLTypeReference", "graphql.schema.GraphQLTypeUtil", "graphql.schema.GraphQLTypeVisitor", From 6ee01b8d1bad802b13dfcc6a16757cfcba63b9d8 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Thu, 21 Aug 2025 20:00:06 +1000 Subject: [PATCH 05/16] Add Nullmarked to GraphQLEnumType --- src/main/java/graphql/schema/GraphQLEnumType.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/graphql/schema/GraphQLEnumType.java b/src/main/java/graphql/schema/GraphQLEnumType.java index 0061d2b810..1700b0b80d 100644 --- a/src/main/java/graphql/schema/GraphQLEnumType.java +++ b/src/main/java/graphql/schema/GraphQLEnumType.java @@ -13,6 +13,7 @@ import graphql.util.FpKit; import graphql.util.TraversalControl; import graphql.util.TraverserContext; +import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.NullUnmarked; import org.jspecify.annotations.Nullable; @@ -41,6 +42,7 @@ * See https://graphql.org/learn/schema/#enumeration-types for more details */ @PublicApi +@NullMarked public class GraphQLEnumType implements GraphQLNamedInputType, GraphQLNamedOutputType, GraphQLUnmodifiedType, GraphQLNullableType, GraphQLDirectiveContainer { private final String name; From a45c613666a563aa74e5890adcccb415de92f74b Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Thu, 21 Aug 2025 20:05:23 +1000 Subject: [PATCH 06/16] Annotate GraphQLCodeRegistry --- src/main/java/graphql/schema/GraphQLCodeRegistry.java | 4 ++++ .../groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/graphql/schema/GraphQLCodeRegistry.java b/src/main/java/graphql/schema/GraphQLCodeRegistry.java index 26574b819c..340c6f0e80 100644 --- a/src/main/java/graphql/schema/GraphQLCodeRegistry.java +++ b/src/main/java/graphql/schema/GraphQLCodeRegistry.java @@ -4,6 +4,8 @@ import graphql.Internal; import graphql.PublicApi; import graphql.schema.visibility.GraphqlFieldVisibility; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.NullUnmarked; import java.util.HashMap; import java.util.LinkedHashMap; @@ -26,6 +28,7 @@ * removed the type system objects will be able have proper hashCode/equals methods and be checked for proper equality. */ @PublicApi +@NullMarked public class GraphQLCodeRegistry { private final Map> dataFetcherMap; @@ -191,6 +194,7 @@ public static Builder newCodeRegistry(GraphQLCodeRegistry existingCodeRegistry) return new Builder(existingCodeRegistry); } + @NullUnmarked public static class Builder { private final Map> dataFetcherMap = new LinkedHashMap<>(); private final Map> systemDataFetcherMap = new LinkedHashMap<>(); diff --git a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy index da730aa5ca..433020b19f 100644 --- a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy +++ b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy @@ -229,7 +229,6 @@ class JSpecifyAnnotationsCheck extends Specification { "graphql.schema.FieldCoordinates", "graphql.schema.GraphQLAppliedDirectiveArgument", "graphql.schema.GraphQLArgument", - "graphql.schema.GraphQLCodeRegistry", "graphql.schema.GraphQLCompositeType", "graphql.schema.GraphQLDirective", "graphql.schema.GraphQLDirectiveContainer", From 70336d52fff03a401344dd803dff5dc7cddf12cc Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Thu, 21 Aug 2025 20:09:09 +1000 Subject: [PATCH 07/16] Annotate GraphQLList --- src/main/java/graphql/schema/GraphQLList.java | 9 +++++---- .../graphql/archunit/JSpecifyAnnotationsCheck.groovy | 1 - 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/graphql/schema/GraphQLList.java b/src/main/java/graphql/schema/GraphQLList.java index 1ac94f5ffe..67792b8323 100644 --- a/src/main/java/graphql/schema/GraphQLList.java +++ b/src/main/java/graphql/schema/GraphQLList.java @@ -4,6 +4,8 @@ import graphql.PublicApi; import graphql.util.TraversalControl; import graphql.util.TraverserContext; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Collections; import java.util.List; @@ -17,15 +19,14 @@ * See https://graphql.org/learn/schema/#lists-and-non-null for more details on the concept */ @PublicApi +@NullMarked public class GraphQLList implements GraphQLType, GraphQLInputType, GraphQLOutputType, GraphQLModifiedType, GraphQLNullableType { - private final GraphQLType originalWrappedType; - private GraphQLType replacedWrappedType; + private @Nullable GraphQLType replacedWrappedType; public static final String CHILD_WRAPPED_TYPE = "wrappedType"; - /** * A factory method for creating list types so that when used with static imports allows * more readable code such as @@ -60,7 +61,7 @@ void replaceType(GraphQLType type) { } - public boolean isEqualTo(Object o) { + public boolean isEqualTo(@Nullable Object o) { if (this == o) { return true; } diff --git a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy index 433020b19f..a17f7651f0 100644 --- a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy +++ b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy @@ -243,7 +243,6 @@ class JSpecifyAnnotationsCheck extends Specification { "graphql.schema.GraphQLInputType", "graphql.schema.GraphQLInputValueDefinition", "graphql.schema.GraphQLInterfaceType", - "graphql.schema.GraphQLList", "graphql.schema.GraphQLModifiedType", "graphql.schema.GraphQLNamedInputType", "graphql.schema.GraphQLNamedOutputType", From 29f836314d2739a5dcd34877edeacffdd99c7d7b Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Thu, 21 Aug 2025 20:12:38 +1000 Subject: [PATCH 08/16] Annotate PropertyDataFetcher --- .../java/graphql/schema/PropertyDataFetcher.java | 15 +++++++++------ .../archunit/JSpecifyAnnotationsCheck.groovy | 1 - 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/graphql/schema/PropertyDataFetcher.java b/src/main/java/graphql/schema/PropertyDataFetcher.java index 38382f4da9..0ac9d107a0 100644 --- a/src/main/java/graphql/schema/PropertyDataFetcher.java +++ b/src/main/java/graphql/schema/PropertyDataFetcher.java @@ -3,6 +3,8 @@ import graphql.Assert; import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -35,10 +37,11 @@ * @see graphql.schema.DataFetcher */ @PublicApi +@NullMarked public class PropertyDataFetcher implements LightDataFetcher { - private final String propertyName; - private final Function function; + private final @Nullable String propertyName; + private final @Nullable Function function; /** * This constructor will use the property name and examine the {@link DataFetchingEnvironment#getSource()} @@ -107,23 +110,23 @@ public static PropertyDataFetcher fetching(Function function) { /** * @return the property that this is fetching for */ - public String getPropertyName() { + public @Nullable String getPropertyName() { return propertyName; } @Override - public T get(GraphQLFieldDefinition fieldDefinition, Object source, Supplier environmentSupplier) throws Exception { + public @Nullable T get(GraphQLFieldDefinition fieldDefinition, Object source, Supplier environmentSupplier) throws Exception { return getImpl(source, fieldDefinition.getType(), environmentSupplier); } @Override - public T get(DataFetchingEnvironment environment) { + public @Nullable T get(DataFetchingEnvironment environment) { Object source = environment.getSource(); return getImpl(source, environment.getFieldType(), () -> environment); } @SuppressWarnings("unchecked") - private T getImpl(Object source, GraphQLOutputType fieldDefinition, Supplier environmentSupplier) { + private @Nullable T getImpl(@Nullable Object source, GraphQLOutputType fieldDefinition, Supplier environmentSupplier) { if (source == null) { return null; } diff --git a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy index a17f7651f0..cd22f25ce9 100644 --- a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy +++ b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy @@ -264,7 +264,6 @@ class JSpecifyAnnotationsCheck extends Specification { "graphql.schema.GraphqlTypeComparatorEnvironment", "graphql.schema.GraphqlTypeComparatorRegistry", "graphql.schema.InputValueWithState", - "graphql.schema.PropertyDataFetcher", "graphql.schema.SchemaElementChildrenContainer", "graphql.schema.SchemaTransformer", "graphql.schema.SchemaTraverser", From 083b2ab146875818b89ae7b4cd80cba98a526c3d Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Thu, 21 Aug 2025 20:16:34 +1000 Subject: [PATCH 09/16] Annotate GraphQLUnionType --- src/main/java/graphql/schema/GraphQLUnionType.java | 6 +++++- .../groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy | 1 - 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/graphql/schema/GraphQLUnionType.java b/src/main/java/graphql/schema/GraphQLUnionType.java index 23a7e9f195..60f17fee3f 100644 --- a/src/main/java/graphql/schema/GraphQLUnionType.java +++ b/src/main/java/graphql/schema/GraphQLUnionType.java @@ -16,7 +16,10 @@ import java.util.List; import java.util.Map; import java.util.function.Consumer; + +import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.NullUnmarked; +import org.jspecify.annotations.Nullable; import static graphql.Assert.assertNotEmpty; import static graphql.Assert.assertNotNull; @@ -36,6 +39,7 @@ * See https://graphql.org/learn/schema/#union-types for more details on the concept. */ @PublicApi +@NullMarked public class GraphQLUnionType implements GraphQLNamedOutputType, GraphQLCompositeType, GraphQLUnmodifiedType, GraphQLNullableType, GraphQLDirectiveContainer { private final String name; @@ -46,7 +50,7 @@ public class GraphQLUnionType implements GraphQLNamedOutputType, GraphQLComposit private final ImmutableList extensionDefinitions; private final DirectivesUtil.DirectivesHolder directives; - private ImmutableList replacedTypes; + private @Nullable ImmutableList replacedTypes; public static final String CHILD_TYPES = "types"; diff --git a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy index cd22f25ce9..ed6d308a4c 100644 --- a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy +++ b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy @@ -258,7 +258,6 @@ class JSpecifyAnnotationsCheck extends Specification { "graphql.schema.GraphQLTypeUtil", "graphql.schema.GraphQLTypeVisitor", "graphql.schema.GraphQLTypeVisitorStub", - "graphql.schema.GraphQLUnionType", "graphql.schema.GraphQLUnmodifiedType", "graphql.schema.GraphqlElementParentTree", "graphql.schema.GraphqlTypeComparatorEnvironment", From b4761ef4f69a5f30e451185c1127a6ac22611395 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Thu, 21 Aug 2025 20:18:36 +1000 Subject: [PATCH 10/16] Tidy up --- src/main/java/graphql/schema/GraphQLEnumType.java | 2 +- src/main/java/graphql/schema/GraphQLType.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/graphql/schema/GraphQLEnumType.java b/src/main/java/graphql/schema/GraphQLEnumType.java index 1700b0b80d..717ad2f99b 100644 --- a/src/main/java/graphql/schema/GraphQLEnumType.java +++ b/src/main/java/graphql/schema/GraphQLEnumType.java @@ -135,7 +135,7 @@ public Value valueToLiteral(Object input, GraphQLContext graphQLContext, Loca GraphQLEnumValueDefinition enumValueDefinition = valueDefinitionMap.get(input.toString()); if (enumValueDefinition == null) { assertShouldNeverHappen(i18nMsg(locale, "Enum.badName", name, input.toString())); - }; + } return EnumValue.newEnumValue(enumValueDefinition.getName()).build(); } diff --git a/src/main/java/graphql/schema/GraphQLType.java b/src/main/java/graphql/schema/GraphQLType.java index a11099a86b..cb332f2f0c 100644 --- a/src/main/java/graphql/schema/GraphQLType.java +++ b/src/main/java/graphql/schema/GraphQLType.java @@ -6,7 +6,7 @@ /** * A type inside the GraphQLSchema. A type doesn't have to have name, e.g. {@link GraphQLList}. - * + *

* See {@link GraphQLNamedType} for types with a name. */ @PublicApi From 9a78fb3622a8320a13327c3391bdf5737f3730e1 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Thu, 21 Aug 2025 20:27:19 +1000 Subject: [PATCH 11/16] Annotate GraphQLScalarType --- .../graphql/schema/GraphQLScalarType.java | 22 ++++++++++--------- .../archunit/JSpecifyAnnotationsCheck.groovy | 1 - 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main/java/graphql/schema/GraphQLScalarType.java b/src/main/java/graphql/schema/GraphQLScalarType.java index bf5442cda9..2c091e3f36 100644 --- a/src/main/java/graphql/schema/GraphQLScalarType.java +++ b/src/main/java/graphql/schema/GraphQLScalarType.java @@ -14,7 +14,10 @@ import java.util.List; import java.util.Map; import java.util.function.Consumer; + +import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.NullUnmarked; +import org.jspecify.annotations.Nullable; import static graphql.Assert.assertNotNull; import static graphql.Assert.assertValidName; @@ -29,7 +32,7 @@ * for example, a GraphQL system could define a scalar called Time which, while serialized as a string, promises to * conform to ISO‐8601. When querying a field of type Time, you can then rely on the ability to parse the result with an ISO‐8601 parser and use a client‐specific primitive for time. *

- * From the spec : https://spec.graphql.org/October2021/#sec-Scalars + * From the spec : ... * *

* graphql-java ships with a set of predefined scalar types via {@link graphql.Scalars} @@ -37,26 +40,26 @@ * @see graphql.Scalars */ @PublicApi -public class -GraphQLScalarType implements GraphQLNamedInputType, GraphQLNamedOutputType, GraphQLUnmodifiedType, GraphQLNullableType, GraphQLDirectiveContainer { +@NullMarked +public class GraphQLScalarType implements GraphQLNamedInputType, GraphQLNamedOutputType, GraphQLUnmodifiedType, GraphQLNullableType, GraphQLDirectiveContainer { private final String name; - private final String description; + private final @Nullable String description; private final Coercing coercing; private final ScalarTypeDefinition definition; private final ImmutableList extensionDefinitions; private final DirectivesUtil.DirectivesHolder directivesHolder; - private final String specifiedByUrl; + private final @Nullable String specifiedByUrl; @Internal private GraphQLScalarType(String name, - String description, + @Nullable String description, Coercing coercing, List directives, List appliedDirectives, ScalarTypeDefinition definition, List extensionDefinitions, - String specifiedByUrl) { + @Nullable String specifiedByUrl) { assertValidName(name); assertNotNull(coercing, () -> "coercing can't be null"); assertNotNull(directives, () -> "directives can't be null"); @@ -76,11 +79,11 @@ public String getName() { } - public String getDescription() { + public @Nullable String getDescription() { return description; } - public String getSpecifiedByUrl() { + public @Nullable String getSpecifiedByUrl() { return specifiedByUrl; } @@ -213,7 +216,6 @@ public static Builder newScalar(GraphQLScalarType existing) { return new Builder(existing); } - @PublicApi @NullUnmarked public static class Builder extends GraphqlDirectivesContainerTypeBuilder { diff --git a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy index ed6d308a4c..f602807076 100644 --- a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy +++ b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy @@ -252,7 +252,6 @@ class JSpecifyAnnotationsCheck extends Specification { "graphql.schema.GraphQLNullableType", "graphql.schema.GraphQLObjectType", "graphql.schema.GraphQLOutputType", - "graphql.schema.GraphQLScalarType", "graphql.schema.GraphQLSchemaElement", "graphql.schema.GraphQLTypeReference", "graphql.schema.GraphQLTypeUtil", From 7bbfd9c62f2ae3fcfa5b6495906c2015c969a9f2 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Thu, 21 Aug 2025 20:28:50 +1000 Subject: [PATCH 12/16] Annotate GraphQLNamedInputType --- src/main/java/graphql/schema/GraphQLNamedInputType.java | 2 ++ .../groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/graphql/schema/GraphQLNamedInputType.java b/src/main/java/graphql/schema/GraphQLNamedInputType.java index d44aeb7bab..493242b7bc 100644 --- a/src/main/java/graphql/schema/GraphQLNamedInputType.java +++ b/src/main/java/graphql/schema/GraphQLNamedInputType.java @@ -2,11 +2,13 @@ import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; /** * Input types represent those set of types that are allowed to be accepted as graphql mutation input, as opposed * to {@link GraphQLOutputType}s which can only be used as graphql response output. */ @PublicApi +@NullMarked public interface GraphQLNamedInputType extends GraphQLInputType, GraphQLNamedType { } diff --git a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy index f602807076..7e684a58a8 100644 --- a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy +++ b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy @@ -244,7 +244,6 @@ class JSpecifyAnnotationsCheck extends Specification { "graphql.schema.GraphQLInputValueDefinition", "graphql.schema.GraphQLInterfaceType", "graphql.schema.GraphQLModifiedType", - "graphql.schema.GraphQLNamedInputType", "graphql.schema.GraphQLNamedOutputType", "graphql.schema.GraphQLNamedSchemaElement", "graphql.schema.GraphQLNamedType", From 7427f644997554179cb3b675932b7be57fdb6e32 Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sat, 23 Aug 2025 16:10:17 +0200 Subject: [PATCH 13/16] Add ErrorType --- src/main/java/graphql/ErrorType.java | 3 +++ src/main/java/graphql/GraphQLError.java | 6 +++--- .../groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy | 3 +-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/graphql/ErrorType.java b/src/main/java/graphql/ErrorType.java index 9adee6d461..0e8d85cfcf 100644 --- a/src/main/java/graphql/ErrorType.java +++ b/src/main/java/graphql/ErrorType.java @@ -1,10 +1,13 @@ package graphql; +import org.jspecify.annotations.NullMarked; + /** * All the errors in graphql belong to one of these categories */ @PublicApi +@NullMarked public enum ErrorType implements ErrorClassification { InvalidSyntax, ValidationError, diff --git a/src/main/java/graphql/GraphQLError.java b/src/main/java/graphql/GraphQLError.java index 90c3527b50..5f4e0412d0 100644 --- a/src/main/java/graphql/GraphQLError.java +++ b/src/main/java/graphql/GraphQLError.java @@ -11,7 +11,7 @@ /** * The interface describing graphql errors - * + *

* NOTE: This class implements {@link java.io.Serializable} and hence it can be serialised and placed into a distributed cache. However we * are not aiming to provide long term compatibility and do not intend for you to place this serialised data into permanent storage, * with times frames that cross graphql-java versions. While we don't change things unnecessarily, we may inadvertently break @@ -42,7 +42,7 @@ public interface GraphQLError extends Serializable { * The graphql spec says that the (optional) path field of any error must be * a list of path entries starting at the root of the response * and ending with the field associated with the error - * https://spec.graphql.org/draft/#sec-Errors.Error-Result-Format + * ... * * @return the path in list format */ @@ -54,7 +54,7 @@ default List getPath() { * The graphql specification says that result of a call should be a map that follows certain rules on what items * should be present. Certain JSON serializers may or may interpret the error to spec, so this method * is provided to produce a map that strictly follows the specification. - * + *

* See : GraphQL Spec - 7.1.2 Errors * * @return a map of the error that strictly follows the specification diff --git a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy index 7e684a58a8..9cc2a047b1 100644 --- a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy +++ b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy @@ -1,4 +1,4 @@ -package graphql +package graphql.archunit import com.tngtech.archunit.core.importer.ClassFileImporter import com.tngtech.archunit.core.importer.ImportOption @@ -14,7 +14,6 @@ class JSpecifyAnnotationsCheck extends Specification { "graphql.AssertException", "graphql.Directives", "graphql.ErrorClassification", - "graphql.ErrorType", "graphql.ExceptionWhileDataFetching", "graphql.ExecutionResult", "graphql.GraphQLContext", From 120095c14f032ac83c77d13ca3853abe97acdccd Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sat, 23 Aug 2025 16:13:03 +0200 Subject: [PATCH 14/16] Annotate Directives --- src/main/java/graphql/Directives.java | 2 ++ .../groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/graphql/Directives.java b/src/main/java/graphql/Directives.java index 37f2b28550..e27c738747 100644 --- a/src/main/java/graphql/Directives.java +++ b/src/main/java/graphql/Directives.java @@ -6,6 +6,7 @@ import graphql.language.DirectiveDefinition; import graphql.language.StringValue; import graphql.schema.GraphQLDirective; +import org.jspecify.annotations.NullMarked; import java.util.concurrent.atomic.AtomicBoolean; @@ -34,6 +35,7 @@ * The directives that are understood by graphql-java */ @PublicApi +@NullMarked public class Directives { private static final String DEPRECATED = "deprecated"; diff --git a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy index 9cc2a047b1..91d2b829ae 100644 --- a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy +++ b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy @@ -12,7 +12,6 @@ class JSpecifyAnnotationsCheck extends Specification { private static final Set JSPECIFY_EXEMPTION_LIST = [ "graphql.AssertException", - "graphql.Directives", "graphql.ErrorClassification", "graphql.ExceptionWhileDataFetching", "graphql.ExecutionResult", From 012f49cbdea2117ced568d8d3689da263582f11d Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sat, 23 Aug 2025 16:16:44 +0200 Subject: [PATCH 15/16] Annotate ErrorClassification --- src/main/java/graphql/ErrorClassification.java | 3 +++ .../groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/graphql/ErrorClassification.java b/src/main/java/graphql/ErrorClassification.java index db9764f2ce..b40ad0e6d7 100644 --- a/src/main/java/graphql/ErrorClassification.java +++ b/src/main/java/graphql/ErrorClassification.java @@ -1,5 +1,7 @@ package graphql; +import org.jspecify.annotations.NullMarked; + /** * Errors in graphql-java can have a classification to help with the processing * of errors. Custom {@link graphql.GraphQLError} implementations could use @@ -8,6 +10,7 @@ * graphql-java ships with a standard set of error classifications via {@link graphql.ErrorType} */ @PublicApi +@NullMarked public interface ErrorClassification { /** diff --git a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy index 91d2b829ae..1ddb760118 100644 --- a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy +++ b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy @@ -12,7 +12,6 @@ class JSpecifyAnnotationsCheck extends Specification { private static final Set JSPECIFY_EXEMPTION_LIST = [ "graphql.AssertException", - "graphql.ErrorClassification", "graphql.ExceptionWhileDataFetching", "graphql.ExecutionResult", "graphql.GraphQLContext", From afdd408ebd4341869b814f97784dbd7bf9b1a59d Mon Sep 17 00:00:00 2001 From: dondonz <13839920+dondonz@users.noreply.github.com> Date: Sat, 23 Aug 2025 16:18:49 +0200 Subject: [PATCH 16/16] Annotate ExceptionWhileDataFetching --- src/main/java/graphql/ExceptionWhileDataFetching.java | 9 ++++++--- .../graphql/archunit/JSpecifyAnnotationsCheck.groovy | 1 - 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/graphql/ExceptionWhileDataFetching.java b/src/main/java/graphql/ExceptionWhileDataFetching.java index 73413f55e0..d5d0c61379 100644 --- a/src/main/java/graphql/ExceptionWhileDataFetching.java +++ b/src/main/java/graphql/ExceptionWhileDataFetching.java @@ -3,6 +3,8 @@ import graphql.execution.ResultPath; import graphql.language.SourceLocation; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Collections; import java.util.LinkedHashMap; @@ -16,13 +18,14 @@ * This graphql error will be used if a runtime exception is encountered while a data fetcher is invoked */ @PublicApi +@NullMarked public class ExceptionWhileDataFetching implements GraphQLError { private final String message; private final List path; private final Throwable exception; private final List locations; - private final Map extensions; + private final @Nullable Map extensions; public ExceptionWhileDataFetching(ResultPath path, Throwable exception, SourceLocation sourceLocation) { this.path = assertNotNull(path).toList(); @@ -41,7 +44,7 @@ private String mkMessage(ResultPath path, Throwable exception) { * exception into the ExceptionWhileDataFetching error and hence have custom "extension attributes" * per error message. */ - private Map mkExtensions(Throwable exception) { + private @Nullable Map mkExtensions(Throwable exception) { Map extensions = null; if (exception instanceof GraphQLError) { Map map = ((GraphQLError) exception).getExtensions(); @@ -73,7 +76,7 @@ public List getPath() { } @Override - public Map getExtensions() { + public @Nullable Map getExtensions() { return extensions; } diff --git a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy index 1ddb760118..ee2ff62efa 100644 --- a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy +++ b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy @@ -12,7 +12,6 @@ class JSpecifyAnnotationsCheck extends Specification { private static final Set JSPECIFY_EXEMPTION_LIST = [ "graphql.AssertException", - "graphql.ExceptionWhileDataFetching", "graphql.ExecutionResult", "graphql.GraphQLContext", "graphql.GraphQLError",