From c60fdf62c681406488614c60dbca4fba8ed54584 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 24 Jan 2026 20:32:22 +0000 Subject: [PATCH 1/5] Initial plan From c02fa4e16fa36db1ac47b4de102e1b492635ba25 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 24 Jan 2026 20:43:06 +0000 Subject: [PATCH 2/5] Add JSpecify annotations to 10 classes in graphql.language package Co-authored-by: dondonz <13839920+dondonz@users.noreply.github.com> --- src/main/java/graphql/language/Comment.java | 9 ++++++--- src/main/java/graphql/language/Definition.java | 2 ++ src/main/java/graphql/language/IgnoredChar.java | 5 ++++- src/main/java/graphql/language/IgnoredChars.java | 2 ++ src/main/java/graphql/language/Node.java | 2 ++ .../graphql/language/NodeChildrenContainer.java | 7 ++++++- src/main/java/graphql/language/NodeVisitor.java | 2 ++ src/main/java/graphql/language/NodeVisitorStub.java | 2 ++ src/main/java/graphql/language/SourceLocation.java | 13 ++++++++----- src/main/java/graphql/language/Type.java | 2 ++ .../archunit/JSpecifyAnnotationsCheck.groovy | 10 ---------- 11 files changed, 36 insertions(+), 20 deletions(-) diff --git a/src/main/java/graphql/language/Comment.java b/src/main/java/graphql/language/Comment.java index a7a546facf..65096c6782 100644 --- a/src/main/java/graphql/language/Comment.java +++ b/src/main/java/graphql/language/Comment.java @@ -1,6 +1,8 @@ package graphql.language; import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.io.Serializable; @@ -8,11 +10,12 @@ * A single-line comment. These are comments that start with a {@code #} in source documents. */ @PublicApi +@NullMarked public class Comment implements Serializable { public final String content; - public final SourceLocation sourceLocation; + public final @Nullable SourceLocation sourceLocation; - public Comment(String content, SourceLocation sourceLocation) { + public Comment(String content, @Nullable SourceLocation sourceLocation) { this.content = content; this.sourceLocation = sourceLocation; } @@ -21,7 +24,7 @@ public String getContent() { return content; } - public SourceLocation getSourceLocation() { + public @Nullable SourceLocation getSourceLocation() { return sourceLocation; } } diff --git a/src/main/java/graphql/language/Definition.java b/src/main/java/graphql/language/Definition.java index f0e7d74dc9..5402bfe3c6 100644 --- a/src/main/java/graphql/language/Definition.java +++ b/src/main/java/graphql/language/Definition.java @@ -2,8 +2,10 @@ import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; @PublicApi +@NullMarked public interface Definition extends Node { } diff --git a/src/main/java/graphql/language/IgnoredChar.java b/src/main/java/graphql/language/IgnoredChar.java index eaa1689d0c..d316a4d6b1 100644 --- a/src/main/java/graphql/language/IgnoredChar.java +++ b/src/main/java/graphql/language/IgnoredChar.java @@ -1,6 +1,8 @@ package graphql.language; import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.io.Serializable; import java.util.Objects; @@ -12,6 +14,7 @@ * This costs more memory but for certain use cases (like editors) this maybe be useful */ @PublicApi +@NullMarked public class IgnoredChar implements Serializable { public enum IgnoredCharKind { @@ -51,7 +54,7 @@ public String toString() { } @Override - public boolean equals(Object o) { + public boolean equals(@Nullable Object o) { if (this == o) { return true; } diff --git a/src/main/java/graphql/language/IgnoredChars.java b/src/main/java/graphql/language/IgnoredChars.java index ce3a1ad59c..241b4cc744 100644 --- a/src/main/java/graphql/language/IgnoredChars.java +++ b/src/main/java/graphql/language/IgnoredChars.java @@ -3,6 +3,7 @@ import com.google.common.collect.ImmutableList; import graphql.PublicApi; import graphql.collect.ImmutableKit; +import org.jspecify.annotations.NullMarked; import java.io.Serializable; import java.util.List; @@ -14,6 +15,7 @@ * This costs more memory but for certain use cases (like editors) this maybe be useful */ @PublicApi +@NullMarked public class IgnoredChars implements Serializable { private final ImmutableList left; diff --git a/src/main/java/graphql/language/Node.java b/src/main/java/graphql/language/Node.java index 962934d76b..917594b876 100644 --- a/src/main/java/graphql/language/Node.java +++ b/src/main/java/graphql/language/Node.java @@ -4,6 +4,7 @@ import graphql.PublicApi; import graphql.util.TraversalControl; import graphql.util.TraverserContext; +import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; import java.io.Serializable; @@ -21,6 +22,7 @@ * Every Node is immutable */ @PublicApi +@NullMarked public interface Node extends Serializable { /** diff --git a/src/main/java/graphql/language/NodeChildrenContainer.java b/src/main/java/graphql/language/NodeChildrenContainer.java index d2e1b06fea..a986ebca76 100644 --- a/src/main/java/graphql/language/NodeChildrenContainer.java +++ b/src/main/java/graphql/language/NodeChildrenContainer.java @@ -1,6 +1,9 @@ package graphql.language; import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.NullUnmarked; +import org.jspecify.annotations.Nullable; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -15,6 +18,7 @@ * Container of children of a {@link Node}. */ @PublicApi +@NullMarked public class NodeChildrenContainer { private final Map> children = new LinkedHashMap<>(); @@ -27,7 +31,7 @@ public List getChildren(String key) { return (List) children.getOrDefault(key, emptyList()); } - public T getChildOrNull(String key) { + public @Nullable T getChildOrNull(String key) { List result = children.getOrDefault(key, emptyList()); if (result.size() > 1) { throw new IllegalStateException("children " + key + " is not a single value"); @@ -61,6 +65,7 @@ public boolean isEmpty() { return this.children.isEmpty(); } + @NullUnmarked public static class Builder { private final Map> children = new LinkedHashMap<>(); diff --git a/src/main/java/graphql/language/NodeVisitor.java b/src/main/java/graphql/language/NodeVisitor.java index 2ed79570b3..ca40709f5d 100644 --- a/src/main/java/graphql/language/NodeVisitor.java +++ b/src/main/java/graphql/language/NodeVisitor.java @@ -3,11 +3,13 @@ import graphql.PublicApi; import graphql.util.TraversalControl; import graphql.util.TraverserContext; +import org.jspecify.annotations.NullMarked; /** * Used by {@link NodeTraverser} to visit {@link Node}. */ @PublicApi +@NullMarked public interface NodeVisitor { TraversalControl visitArgument(Argument node, TraverserContext data); diff --git a/src/main/java/graphql/language/NodeVisitorStub.java b/src/main/java/graphql/language/NodeVisitorStub.java index f0fcd6b3fd..b5d00073c4 100644 --- a/src/main/java/graphql/language/NodeVisitorStub.java +++ b/src/main/java/graphql/language/NodeVisitorStub.java @@ -3,11 +3,13 @@ import graphql.PublicApi; import graphql.util.TraversalControl; import graphql.util.TraverserContext; +import org.jspecify.annotations.NullMarked; /** * Convenient implementation of {@link NodeVisitor} for easy subclassing methods handling different types of Nodes in one method. */ @PublicApi +@NullMarked public class NodeVisitorStub implements NodeVisitor { @Override public TraversalControl visitArgument(Argument node, TraverserContext context) { diff --git a/src/main/java/graphql/language/SourceLocation.java b/src/main/java/graphql/language/SourceLocation.java index a4ae90a039..b97cc103ac 100644 --- a/src/main/java/graphql/language/SourceLocation.java +++ b/src/main/java/graphql/language/SourceLocation.java @@ -7,24 +7,27 @@ import graphql.schema.GraphQLSchemaElement; import graphql.schema.GraphQLTypeUtil; import graphql.schema.idl.SchemaGenerator; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.io.Serializable; import java.util.Objects; @PublicApi +@NullMarked public class SourceLocation implements Serializable { public static final SourceLocation EMPTY = new SourceLocation(-1, -1); private final int line; private final int column; - private final String sourceName; + private final @Nullable String sourceName; public SourceLocation(int line, int column) { this(line, column, null); } - public SourceLocation(int line, int column, String sourceName) { + public SourceLocation(int line, int column, @Nullable String sourceName) { this.line = line; this.column = column; this.sourceName = sourceName; @@ -38,12 +41,12 @@ public int getColumn() { return column; } - public String getSourceName() { + public @Nullable String getSourceName() { return sourceName; } @Override - public boolean equals(Object o) { + public boolean equals(@Nullable Object o) { if (this == o) { return true; } @@ -91,7 +94,7 @@ public String toString() { * * @return the source location if available or null if it's not. */ - public static SourceLocation getLocation(GraphQLSchemaElement schemaElement) { + public static @Nullable SourceLocation getLocation(GraphQLSchemaElement schemaElement) { if (schemaElement instanceof GraphQLModifiedType) { schemaElement = GraphQLTypeUtil.unwrapAllAs((GraphQLModifiedType) schemaElement); } diff --git a/src/main/java/graphql/language/Type.java b/src/main/java/graphql/language/Type.java index a3141e56d0..85d06564de 100644 --- a/src/main/java/graphql/language/Type.java +++ b/src/main/java/graphql/language/Type.java @@ -2,8 +2,10 @@ import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; @PublicApi +@NullMarked public interface Type extends Node { } diff --git a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy index 994c835aab..7116b1641a 100644 --- a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy +++ b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy @@ -109,8 +109,6 @@ class JSpecifyAnnotationsCheck extends Specification { "graphql.language.AstSignature", "graphql.language.AstSorter", "graphql.language.AstTransformer", - "graphql.language.Comment", - "graphql.language.Definition", "graphql.language.DescribedNode", "graphql.language.Description", "graphql.language.Directive", @@ -125,8 +123,6 @@ class JSpecifyAnnotationsCheck extends Specification { "graphql.language.FieldDefinition", "graphql.language.FragmentDefinition", "graphql.language.FragmentSpread", - "graphql.language.IgnoredChar", - "graphql.language.IgnoredChars", "graphql.language.ImplementingTypeDefinition", "graphql.language.InlineFragment", "graphql.language.InputObjectTypeDefinition", @@ -135,13 +131,9 @@ class JSpecifyAnnotationsCheck extends Specification { "graphql.language.InterfaceTypeDefinition", "graphql.language.InterfaceTypeExtensionDefinition", "graphql.language.ListType", - "graphql.language.Node", - "graphql.language.NodeChildrenContainer", "graphql.language.NodeDirectivesBuilder", "graphql.language.NodeParentTree", "graphql.language.NodeTraverser", - "graphql.language.NodeVisitor", - "graphql.language.NodeVisitorStub", "graphql.language.NonNullType", "graphql.language.ObjectField", "graphql.language.ObjectTypeDefinition", @@ -159,8 +151,6 @@ class JSpecifyAnnotationsCheck extends Specification { "graphql.language.Selection", "graphql.language.SelectionSet", "graphql.language.SelectionSetContainer", - "graphql.language.SourceLocation", - "graphql.language.Type", "graphql.language.TypeDefinition", "graphql.language.TypeKind", "graphql.language.TypeName", From 3db2ddeae4f403850111cb8c356d0532dd0bbce4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 24 Jan 2026 21:26:08 +0000 Subject: [PATCH 3/5] Update JSpecify annotation prompt with effectiveness improvements Co-authored-by: dondonz <13839920+dondonz@users.noreply.github.com> --- .claude/commands/jspecify-annotate.md | 69 ++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/.claude/commands/jspecify-annotate.md b/.claude/commands/jspecify-annotate.md index 48d385ea1a..f1644de717 100644 --- a/.claude/commands/jspecify-annotate.md +++ b/.claude/commands/jspecify-annotate.md @@ -4,6 +4,14 @@ Note that JSpecify is already used in this repository so it's already imported. 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. +## Batch Size and Prioritization + +Annotate approximately 10 classes per batch for optimal context management. Start with interface/simple classes first, then tackle complex classes with builders. This helps identify patterns early. + +## Exploration Phase + +Before annotating, use `grep` to search for how each class is instantiated (e.g., `grep -r "new Comment"`) to understand which parameters can be null. Check constructor calls, method returns, and field assignments to inform your nullability decisions. + Analyze this Java class and add JSpecify annotations based on: 1. Set the class to be `@NullMarked` 2. Remove all the redundant `@NonNull` annotations that IntelliJ added @@ -14,6 +22,62 @@ Analyze this Java class and add JSpecify annotations based on: IntelliJ's infer nullity code analysis isn't comprehensive so feel free to make corrections. +## Pattern Examples + +Here are concrete examples of common annotation patterns: + +**Interface:** +```java +@PublicApi +@NullMarked +public interface MyInterface { + // Methods inherit @NullMarked context +} +``` + +**Class with nullable field:** +```java +@PublicApi +@NullMarked +public class Comment { + private final String content; + private final @Nullable SourceLocation sourceLocation; + + public Comment(String content, @Nullable SourceLocation sourceLocation) { + this.content = content; + this.sourceLocation = sourceLocation; + } + + public @Nullable SourceLocation getSourceLocation() { + return sourceLocation; + } +} +``` + +**Class with nullable return type:** +```java +@PublicApi +@NullMarked +public class Container { + public @Nullable Node getChildOrNull(String key) { + // May return null + return children.get(key); + } +} +``` + +**Builder with @NullUnmarked:** +```java +@PublicApi +@NullMarked +public class MyClass { + @NullUnmarked + public static class Builder { + // No further annotations needed in builder + } +} +``` + ## GraphQL Specification Compliance This is a GraphQL implementation. When determining nullability, consult the GraphQL specification (https://spec.graphql.org/draft/) for the relevant concept. Key principles: @@ -21,7 +85,10 @@ The spec defines which elements are required (non-null) vs optional (nullable). If a class implements or represents a GraphQL specification concept, prioritize the spec's nullability requirements over what IntelliJ inferred. -## How to validate +## Validation Strategy + +Run `./gradlew compileJava` after every 3-5 classes annotated, not just at the end. This catches issues early and makes debugging easier. + Finally, please check all this works by running the NullAway compile check. If you find NullAway errors, try and make the smallest possible change to fix them. If you must, you can use assertNotNull. Make sure to include a message as well. From 4bdefd7c3f22ef3c99116ed18cbeb2058fd27de7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 25 Jan 2026 06:36:44 +0000 Subject: [PATCH 4/5] Initial plan From ffadaba86d379b83031be9ef23005c4e4172dc59 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 25 Jan 2026 07:10:13 +0000 Subject: [PATCH 5/5] Add JSpecify annotations to 14 classes in graphql.language package Co-authored-by: dondonz <13839920+dondonz@users.noreply.github.com> --- .../graphql/language/SDLNamedDefinition.java | 2 ++ .../language/ScalarTypeDefinition.java | 13 +++++++---- .../ScalarTypeExtensionDefinition.java | 11 ++++++--- .../graphql/language/SchemaDefinition.java | 15 ++++++++---- .../language/SchemaExtensionDefinition.java | 9 ++++++-- src/main/java/graphql/language/Selection.java | 2 ++ .../java/graphql/language/SelectionSet.java | 11 ++++++--- .../language/SelectionSetContainer.java | 5 +++- .../java/graphql/language/TypeDefinition.java | 2 ++ src/main/java/graphql/language/TypeKind.java | 2 ++ src/main/java/graphql/language/TypeName.java | 10 +++++--- .../graphql/language/UnionTypeDefinition.java | 15 ++++++++---- .../UnionTypeExtensionDefinition.java | 13 +++++++---- .../graphql/language/VariableDefinition.java | 23 +++++++++++-------- src/main/java/graphql/util/Anonymizer.java | 4 ++-- .../archunit/JSpecifyAnnotationsCheck.groovy | 14 ----------- 16 files changed, 96 insertions(+), 55 deletions(-) diff --git a/src/main/java/graphql/language/SDLNamedDefinition.java b/src/main/java/graphql/language/SDLNamedDefinition.java index 44b4bf85a6..c773761424 100644 --- a/src/main/java/graphql/language/SDLNamedDefinition.java +++ b/src/main/java/graphql/language/SDLNamedDefinition.java @@ -2,6 +2,7 @@ import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; /** * A interface for named Schema Definition Language (SDL) definition. @@ -9,6 +10,7 @@ * @param the actual Node type */ @PublicApi +@NullMarked public interface SDLNamedDefinition extends SDLDefinition { /** diff --git a/src/main/java/graphql/language/ScalarTypeDefinition.java b/src/main/java/graphql/language/ScalarTypeDefinition.java index 3374b69dab..3a00a9694d 100644 --- a/src/main/java/graphql/language/ScalarTypeDefinition.java +++ b/src/main/java/graphql/language/ScalarTypeDefinition.java @@ -7,6 +7,9 @@ import graphql.collect.ImmutableKit; 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; @@ -20,6 +23,7 @@ import static graphql.language.NodeChildrenContainer.newNodeChildrenContainer; @PublicApi +@NullMarked public class ScalarTypeDefinition extends AbstractDescribedNode implements TypeDefinition, DirectivesContainer, NamedNode { private final String name; @@ -30,8 +34,8 @@ public class ScalarTypeDefinition extends AbstractDescribedNode directives, - Description description, - SourceLocation sourceLocation, + @Nullable Description description, + @Nullable SourceLocation sourceLocation, List comments, IgnoredChars ignoredChars, Map additionalData) { @@ -94,7 +98,7 @@ public ScalarTypeDefinition withNewChildren(NodeChildrenContainer newChildren) { } @Override - public boolean isEqualTo(Node o) { + public boolean isEqualTo(@Nullable Node o) { if (this == o) { return true; } @@ -109,7 +113,7 @@ public boolean isEqualTo(Node o) { @Override public ScalarTypeDefinition deepCopy() { - return new ScalarTypeDefinition(name, deepCopy(directives.getDirectives()), description, getSourceLocation(), getComments(), getIgnoredChars(), getAdditionalData()); + return new ScalarTypeDefinition(name, assertNotNull(deepCopy(directives.getDirectives())), description, getSourceLocation(), getComments(), getIgnoredChars(), getAdditionalData()); } @Override @@ -135,6 +139,7 @@ public ScalarTypeDefinition transform(Consumer builderConsumer) { return builder.build(); } + @NullUnmarked public static final class Builder implements NodeDirectivesBuilder { private SourceLocation sourceLocation; private ImmutableList comments = emptyList(); diff --git a/src/main/java/graphql/language/ScalarTypeExtensionDefinition.java b/src/main/java/graphql/language/ScalarTypeExtensionDefinition.java index 0feb48451b..97fa892454 100644 --- a/src/main/java/graphql/language/ScalarTypeExtensionDefinition.java +++ b/src/main/java/graphql/language/ScalarTypeExtensionDefinition.java @@ -4,6 +4,9 @@ import graphql.Internal; import graphql.PublicApi; import graphql.collect.ImmutableKit; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.NullUnmarked; +import org.jspecify.annotations.Nullable; import java.util.LinkedHashMap; import java.util.List; @@ -14,13 +17,14 @@ import static graphql.collect.ImmutableKit.emptyList; @PublicApi +@NullMarked public class ScalarTypeExtensionDefinition extends ScalarTypeDefinition implements SDLExtensionDefinition { @Internal protected ScalarTypeExtensionDefinition(String name, List directives, - Description description, - SourceLocation sourceLocation, + @Nullable Description description, + @Nullable SourceLocation sourceLocation, List comments, IgnoredChars ignoredChars, Map additionalData) { super(name, directives, description, sourceLocation, comments, ignoredChars, additionalData); @@ -28,7 +32,7 @@ protected ScalarTypeExtensionDefinition(String name, @Override public ScalarTypeExtensionDefinition deepCopy() { - return new ScalarTypeExtensionDefinition(getName(), deepCopy(getDirectives()), getDescription(), getSourceLocation(), getComments(), getIgnoredChars(), getAdditionalData()); + return new ScalarTypeExtensionDefinition(getName(), assertNotNull(deepCopy(getDirectives())), getDescription(), getSourceLocation(), getComments(), getIgnoredChars(), getAdditionalData()); } @Override @@ -57,6 +61,7 @@ public ScalarTypeExtensionDefinition transformExtension(Consumer builde return builder.build(); } + @NullUnmarked public static final class Builder implements NodeDirectivesBuilder { private SourceLocation sourceLocation; private ImmutableList comments = emptyList(); diff --git a/src/main/java/graphql/language/SchemaDefinition.java b/src/main/java/graphql/language/SchemaDefinition.java index 931ef33c41..261ba76cab 100644 --- a/src/main/java/graphql/language/SchemaDefinition.java +++ b/src/main/java/graphql/language/SchemaDefinition.java @@ -8,6 +8,9 @@ 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; import java.util.LinkedHashMap; import java.util.List; @@ -19,6 +22,7 @@ import static graphql.language.NodeChildrenContainer.newNodeChildrenContainer; @PublicApi +@NullMarked public class SchemaDefinition extends AbstractDescribedNode implements SDLDefinition, DirectivesContainer { private final NodeUtil.DirectivesHolder directives; @@ -31,11 +35,11 @@ public class SchemaDefinition extends AbstractDescribedNode im @Internal protected SchemaDefinition(List directives, List operationTypeDefinitions, - SourceLocation sourceLocation, + @Nullable SourceLocation sourceLocation, List comments, IgnoredChars ignoredChars, Map additionalData, - Description description) { + @Nullable Description description) { super(sourceLocation, comments, ignoredChars, additionalData, description); this.directives = NodeUtil.DirectivesHolder.of(directives); this.operationTypeDefinitions = ImmutableList.copyOf(operationTypeDefinitions); @@ -65,7 +69,7 @@ public List getOperationTypeDefinitions() { return operationTypeDefinitions; } - public Description getDescription() { + public @Nullable Description getDescription() { return description; } @@ -91,7 +95,7 @@ public SchemaDefinition withNewChildren(NodeChildrenContainer newChildren) { } @Override - public boolean isEqualTo(Node o) { + public boolean isEqualTo(@Nullable Node o) { if (this == o) { return true; } @@ -103,7 +107,7 @@ public boolean isEqualTo(Node o) { @Override public SchemaDefinition deepCopy() { - return new SchemaDefinition(deepCopy(directives.getDirectives()), deepCopy(operationTypeDefinitions), getSourceLocation(), getComments(), + return new SchemaDefinition(assertNotNull(deepCopy(directives.getDirectives())), assertNotNull(deepCopy(operationTypeDefinitions)), getSourceLocation(), getComments(), getIgnoredChars(), getAdditionalData(), description); } @@ -130,6 +134,7 @@ public static Builder newSchemaDefinition() { return new Builder(); } + @NullUnmarked public static final class Builder implements NodeBuilder { private SourceLocation sourceLocation; private ImmutableList comments = emptyList(); diff --git a/src/main/java/graphql/language/SchemaExtensionDefinition.java b/src/main/java/graphql/language/SchemaExtensionDefinition.java index 43927f5b92..86a15bf651 100644 --- a/src/main/java/graphql/language/SchemaExtensionDefinition.java +++ b/src/main/java/graphql/language/SchemaExtensionDefinition.java @@ -3,6 +3,9 @@ import com.google.common.collect.ImmutableList; import graphql.PublicApi; import graphql.collect.ImmutableKit; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.NullUnmarked; +import org.jspecify.annotations.Nullable; import java.util.LinkedHashMap; import java.util.List; @@ -13,11 +16,12 @@ import static graphql.collect.ImmutableKit.emptyList; @PublicApi +@NullMarked public class SchemaExtensionDefinition extends SchemaDefinition implements SDLExtensionDefinition { protected SchemaExtensionDefinition(List directives, List operationTypeDefinitions, - SourceLocation sourceLocation, + @Nullable SourceLocation sourceLocation, List comments, IgnoredChars ignoredChars, Map additionalData) { @@ -34,7 +38,7 @@ public SchemaExtensionDefinition withNewChildren(NodeChildrenContainer newChildr @Override public SchemaExtensionDefinition deepCopy() { - return new SchemaExtensionDefinition(deepCopy(getDirectives()), deepCopy(getOperationTypeDefinitions()), getSourceLocation(), getComments(), + return new SchemaExtensionDefinition(assertNotNull(deepCopy(getDirectives())), assertNotNull(deepCopy(getOperationTypeDefinitions())), getSourceLocation(), getComments(), getIgnoredChars(), getAdditionalData()); } @@ -56,6 +60,7 @@ public static Builder newSchemaExtensionDefinition() { return new Builder(); } + @NullUnmarked public static final class Builder implements NodeDirectivesBuilder { private SourceLocation sourceLocation; private ImmutableList comments = emptyList(); diff --git a/src/main/java/graphql/language/Selection.java b/src/main/java/graphql/language/Selection.java index 7160ccfafe..db2dea5d01 100644 --- a/src/main/java/graphql/language/Selection.java +++ b/src/main/java/graphql/language/Selection.java @@ -2,7 +2,9 @@ import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; @PublicApi +@NullMarked public interface Selection> extends Node { } diff --git a/src/main/java/graphql/language/SelectionSet.java b/src/main/java/graphql/language/SelectionSet.java index 8e85bdcdef..8133355836 100644 --- a/src/main/java/graphql/language/SelectionSet.java +++ b/src/main/java/graphql/language/SelectionSet.java @@ -7,6 +7,9 @@ import graphql.collect.ImmutableKit; 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.Collection; import java.util.LinkedHashMap; @@ -20,6 +23,7 @@ import static graphql.language.NodeChildrenContainer.newNodeChildrenContainer; @PublicApi +@NullMarked public class SelectionSet extends AbstractNode { private final ImmutableList selections; @@ -27,7 +31,7 @@ public class SelectionSet extends AbstractNode { public static final String CHILD_SELECTIONS = "selections"; @Internal - protected SelectionSet(Collection selections, SourceLocation sourceLocation, List comments, IgnoredChars ignoredChars, Map additionalData) { + protected SelectionSet(Collection selections, @Nullable SourceLocation sourceLocation, List comments, IgnoredChars ignoredChars, Map additionalData) { super(sourceLocation, comments, ignoredChars, additionalData); this.selections = ImmutableList.copyOf(selections); } @@ -79,7 +83,7 @@ public SelectionSet withNewChildren(NodeChildrenContainer newChildren) { } @Override - public boolean isEqualTo(Node o) { + public boolean isEqualTo(@Nullable Node o) { if (this == o) { return true; } @@ -92,7 +96,7 @@ public boolean isEqualTo(Node o) { @Override public SelectionSet deepCopy() { - return new SelectionSet(deepCopy(selections), getSourceLocation(), getComments(), getIgnoredChars(), getAdditionalData()); + return new SelectionSet(assertNotNull(deepCopy(selections)), getSourceLocation(), getComments(), getIgnoredChars(), getAdditionalData()); } @Override @@ -121,6 +125,7 @@ public SelectionSet transform(Consumer builderConsumer) { return builder.build(); } + @NullUnmarked public static final class Builder implements NodeBuilder { private ImmutableList selections = emptyList(); diff --git a/src/main/java/graphql/language/SelectionSetContainer.java b/src/main/java/graphql/language/SelectionSetContainer.java index d3df7af419..b0e24d3a5d 100644 --- a/src/main/java/graphql/language/SelectionSetContainer.java +++ b/src/main/java/graphql/language/SelectionSetContainer.java @@ -2,8 +2,11 @@ import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; @PublicApi +@NullMarked public interface SelectionSetContainer extends Node { - SelectionSet getSelectionSet(); + @Nullable SelectionSet getSelectionSet(); } diff --git a/src/main/java/graphql/language/TypeDefinition.java b/src/main/java/graphql/language/TypeDefinition.java index f75c2c5147..8a5418cd2b 100644 --- a/src/main/java/graphql/language/TypeDefinition.java +++ b/src/main/java/graphql/language/TypeDefinition.java @@ -2,6 +2,7 @@ import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; /** * An interface for type definitions in a Schema Definition Language (SDL). @@ -9,6 +10,7 @@ * @param the actual Node type */ @PublicApi +@NullMarked public interface TypeDefinition extends SDLNamedDefinition, DirectivesContainer, NamedNode { } diff --git a/src/main/java/graphql/language/TypeKind.java b/src/main/java/graphql/language/TypeKind.java index 2af70b18f2..8d96e20c55 100644 --- a/src/main/java/graphql/language/TypeKind.java +++ b/src/main/java/graphql/language/TypeKind.java @@ -2,11 +2,13 @@ import graphql.Assert; import graphql.PublicApi; +import org.jspecify.annotations.NullMarked; /** * And enumeration of the the kind of things that can be in a graphql type system */ @PublicApi +@NullMarked public enum TypeKind { Operation, Object, Interface, Union, Enum, Scalar, InputObject; diff --git a/src/main/java/graphql/language/TypeName.java b/src/main/java/graphql/language/TypeName.java index add06add41..cbf946cd19 100644 --- a/src/main/java/graphql/language/TypeName.java +++ b/src/main/java/graphql/language/TypeName.java @@ -6,6 +6,9 @@ import graphql.PublicApi; 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; @@ -20,12 +23,13 @@ import static graphql.language.NodeUtil.assertNewChildrenAreEmpty; @PublicApi +@NullMarked public class TypeName extends AbstractNode implements Type, NamedNode { private final String name; @Internal - protected TypeName(String name, SourceLocation sourceLocation, List comments, IgnoredChars ignoredChars, Map additionalData) { + protected TypeName(String name, @Nullable SourceLocation sourceLocation, List comments, IgnoredChars ignoredChars, Map additionalData) { super(sourceLocation, comments, ignoredChars, additionalData); this.name = name; } @@ -61,7 +65,7 @@ public TypeName withNewChildren(NodeChildrenContainer newChildren) { } @Override - public boolean isEqualTo(Node o) { + public boolean isEqualTo(@Nullable Node o) { if (this == o) { return true; } @@ -105,7 +109,7 @@ public TypeName transform(Consumer builderConsumer) { return builder.build(); } - + @NullUnmarked public static final class Builder implements NodeBuilder { private String name; private SourceLocation sourceLocation; diff --git a/src/main/java/graphql/language/UnionTypeDefinition.java b/src/main/java/graphql/language/UnionTypeDefinition.java index 9af502db89..5315c57f92 100644 --- a/src/main/java/graphql/language/UnionTypeDefinition.java +++ b/src/main/java/graphql/language/UnionTypeDefinition.java @@ -8,6 +8,9 @@ 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; import java.util.LinkedHashMap; import java.util.List; @@ -21,6 +24,7 @@ import static graphql.language.NodeChildrenContainer.newNodeChildrenContainer; @PublicApi +@NullMarked public class UnionTypeDefinition extends AbstractDescribedNode implements TypeDefinition, DirectivesContainer, NamedNode { private final String name; @@ -34,8 +38,8 @@ public class UnionTypeDefinition extends AbstractDescribedNode directives, List memberTypes, - Description description, - SourceLocation sourceLocation, + @Nullable Description description, + @Nullable SourceLocation sourceLocation, List comments, IgnoredChars ignoredChars, Map additionalData) { super(sourceLocation, comments, ignoredChars, additionalData, description); @@ -115,7 +119,7 @@ public UnionTypeDefinition withNewChildren(NodeChildrenContainer newChildren) { } @Override - public boolean isEqualTo(Node o) { + public boolean isEqualTo(@Nullable Node o) { if (this == o) { return true; } @@ -131,8 +135,8 @@ public boolean isEqualTo(Node o) { @Override public UnionTypeDefinition deepCopy() { return new UnionTypeDefinition(name, - deepCopy(directives.getDirectives()), - deepCopy(memberTypes), + assertNotNull(deepCopy(directives.getDirectives())), + assertNotNull(deepCopy(memberTypes)), description, getSourceLocation(), getComments(), @@ -164,6 +168,7 @@ public UnionTypeDefinition transform(Consumer builderConsumer) { return builder.build(); } + @NullUnmarked public static final class Builder implements NodeDirectivesBuilder { private SourceLocation sourceLocation; private ImmutableList comments = emptyList(); diff --git a/src/main/java/graphql/language/UnionTypeExtensionDefinition.java b/src/main/java/graphql/language/UnionTypeExtensionDefinition.java index 81ea751792..0d53d40b49 100644 --- a/src/main/java/graphql/language/UnionTypeExtensionDefinition.java +++ b/src/main/java/graphql/language/UnionTypeExtensionDefinition.java @@ -4,6 +4,9 @@ import graphql.Internal; import graphql.PublicApi; import graphql.collect.ImmutableKit; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.NullUnmarked; +import org.jspecify.annotations.Nullable; import java.util.LinkedHashMap; import java.util.List; @@ -14,14 +17,15 @@ import static graphql.collect.ImmutableKit.emptyList; @PublicApi +@NullMarked public class UnionTypeExtensionDefinition extends UnionTypeDefinition implements SDLExtensionDefinition { @Internal protected UnionTypeExtensionDefinition(String name, List directives, List memberTypes, - Description description, - SourceLocation sourceLocation, + @Nullable Description description, + @Nullable SourceLocation sourceLocation, List comments, IgnoredChars ignoredChars, Map additionalData) { @@ -38,8 +42,8 @@ protected UnionTypeExtensionDefinition(String name, @Override public UnionTypeExtensionDefinition deepCopy() { return new UnionTypeExtensionDefinition(getName(), - deepCopy(getDirectives()), - deepCopy(getMemberTypes()), + assertNotNull(deepCopy(getDirectives())), + assertNotNull(deepCopy(getMemberTypes())), getDescription(), getSourceLocation(), getComments(), @@ -73,6 +77,7 @@ public UnionTypeExtensionDefinition transformExtension(Consumer builder return builder.build(); } + @NullUnmarked public static final class Builder implements NodeDirectivesBuilder { private SourceLocation sourceLocation; private ImmutableList comments = emptyList(); diff --git a/src/main/java/graphql/language/VariableDefinition.java b/src/main/java/graphql/language/VariableDefinition.java index c119222d47..a05439bcd3 100644 --- a/src/main/java/graphql/language/VariableDefinition.java +++ b/src/main/java/graphql/language/VariableDefinition.java @@ -7,6 +7,9 @@ import graphql.collect.ImmutableKit; 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.ArrayList; import java.util.LinkedHashMap; @@ -21,11 +24,12 @@ import static graphql.language.NodeChildrenContainer.newNodeChildrenContainer; @PublicApi +@NullMarked public class VariableDefinition extends AbstractNode implements DirectivesContainer, NamedNode { private final String name; private final Type type; - private final Value defaultValue; + private final @Nullable Value defaultValue; private final NodeUtil.DirectivesHolder directives; public static final String CHILD_TYPE = "type"; @@ -35,9 +39,9 @@ public class VariableDefinition extends AbstractNode impleme @Internal protected VariableDefinition(String name, Type type, - Value defaultValue, + @Nullable Value defaultValue, List directives, - SourceLocation sourceLocation, + @Nullable SourceLocation sourceLocation, List comments, IgnoredChars ignoredChars, Map additionalData) { @@ -57,7 +61,7 @@ protected VariableDefinition(String name, */ public VariableDefinition(String name, Type type, - Value defaultValue) { + @Nullable Value defaultValue) { this(name, type, defaultValue, emptyList(), null, emptyList(), IgnoredChars.EMPTY, emptyMap()); } @@ -72,7 +76,7 @@ public VariableDefinition(String name, this(name, type, null, emptyList(), null, emptyList(), IgnoredChars.EMPTY, emptyMap()); } - public Value getDefaultValue() { + public @Nullable Value getDefaultValue() { return defaultValue; } @@ -134,7 +138,7 @@ public VariableDefinition withNewChildren(NodeChildrenContainer newChildren) { } @Override - public boolean isEqualTo(Node o) { + public boolean isEqualTo(@Nullable Node o) { if (this == o) { return true; } @@ -151,9 +155,9 @@ public boolean isEqualTo(Node o) { @Override public VariableDefinition deepCopy() { return new VariableDefinition(name, - deepCopy(type), + assertNotNull(deepCopy(type)), deepCopy(defaultValue), - deepCopy(directives.getDirectives()), + assertNotNull(deepCopy(directives.getDirectives())), getSourceLocation(), getComments(), getIgnoredChars(), @@ -188,7 +192,7 @@ public static Builder newVariableDefinition(String name, Type type) { return new Builder().name(name).type(type); } - public static Builder newVariableDefinition(String name, Type type, Value defaultValue) { + public static Builder newVariableDefinition(String name, Type type, @Nullable Value defaultValue) { return new Builder().name(name).type(type).defaultValue(defaultValue); } @@ -198,6 +202,7 @@ public VariableDefinition transform(Consumer builderConsumer) { return builder.build(); } + @NullUnmarked public static final class Builder implements NodeDirectivesBuilder { private SourceLocation sourceLocation; private String name; diff --git a/src/main/java/graphql/util/Anonymizer.java b/src/main/java/graphql/util/Anonymizer.java index e58a67ed17..3f23777101 100644 --- a/src/main/java/graphql/util/Anonymizer.java +++ b/src/main/java/graphql/util/Anonymizer.java @@ -865,14 +865,14 @@ public TraversalControl visitVariableReference(VariableReference node, Traverser public TraversalControl visitFragmentDefinition(FragmentDefinition node, TraverserContext context) { String newName = assertNotNull(astNodeToNewName.get(node)); GraphQLType currentCondition = assertNotNull(schema.getType(node.getTypeCondition().getName())); - String newCondition = newNames.get(currentCondition); + String newCondition = assertNotNull(newNames.get(currentCondition)); return changeNode(context, node.transform(builder -> builder.name(newName).typeCondition(new TypeName(newCondition)))); } @Override public TraversalControl visitInlineFragment(InlineFragment node, TraverserContext context) { GraphQLType currentCondition = assertNotNull(schema.getType(node.getTypeCondition().getName())); - String newCondition = newNames.get(currentCondition); + String newCondition = assertNotNull(newNames.get(currentCondition)); return changeNode(context, node.transform(builder -> builder.typeCondition(new TypeName(newCondition)))); } diff --git a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy index 7116b1641a..553d640b00 100644 --- a/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy +++ b/src/test/groovy/graphql/archunit/JSpecifyAnnotationsCheck.groovy @@ -143,20 +143,6 @@ class JSpecifyAnnotationsCheck extends Specification { "graphql.language.PrettyAstPrinter", "graphql.language.SDLDefinition", "graphql.language.SDLExtensionDefinition", - "graphql.language.SDLNamedDefinition", - "graphql.language.ScalarTypeDefinition", - "graphql.language.ScalarTypeExtensionDefinition", - "graphql.language.SchemaDefinition", - "graphql.language.SchemaExtensionDefinition", - "graphql.language.Selection", - "graphql.language.SelectionSet", - "graphql.language.SelectionSetContainer", - "graphql.language.TypeDefinition", - "graphql.language.TypeKind", - "graphql.language.TypeName", - "graphql.language.UnionTypeDefinition", - "graphql.language.UnionTypeExtensionDefinition", - "graphql.language.VariableDefinition", "graphql.normalized.ExecutableNormalizedField", "graphql.normalized.ExecutableNormalizedOperation", "graphql.normalized.ExecutableNormalizedOperationFactory",