From afbcd52285065393ebb326a2ce4871daf36c700e Mon Sep 17 00:00:00 2001 From: bbaker Date: Fri, 19 Dec 2025 10:22:11 +1100 Subject: [PATCH 1/2] #4182 - code built schemas should perform deprecated non null field validations as well as SDL built ones --- ...ecatedInputObjectAndArgumentsAreValid.java | 16 ++++++--- ...InputObjectAndArgumentsAreValidTest.groovy | 33 +++++++++++++++++++ 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/main/java/graphql/schema/validation/DeprecatedInputObjectAndArgumentsAreValid.java b/src/main/java/graphql/schema/validation/DeprecatedInputObjectAndArgumentsAreValid.java index ce619223cc..aaeda507a8 100644 --- a/src/main/java/graphql/schema/validation/DeprecatedInputObjectAndArgumentsAreValid.java +++ b/src/main/java/graphql/schema/validation/DeprecatedInputObjectAndArgumentsAreValid.java @@ -42,10 +42,8 @@ public TraversalControl visitGraphQLInputObjectField(GraphQLInputObjectField inp // An applied directive's argument cannot be deprecated. @Override public TraversalControl visitGraphQLArgument(GraphQLArgument argument, TraverserContext context) { - // There can only be at most one @deprecated, because it is not a repeatable directive - GraphQLAppliedDirective deprecatedDirective = argument.getAppliedDirective(Directives.DEPRECATED_DIRECTIVE_DEFINITION.getName()); - - if (deprecatedDirective != null && GraphQLTypeUtil.isNonNull(argument.getType()) && !argument.hasSetDefaultValue()) { + boolean isDeprecated = isDeprecated(argument); + if (isDeprecated && GraphQLTypeUtil.isNonNull(argument.getType()) && !argument.hasSetDefaultValue()) { if (context.getParentNode() instanceof GraphQLFieldDefinition) { GraphQLFieldDefinition fieldDefinition = (GraphQLFieldDefinition) context.getParentNode(); SchemaValidationErrorCollector errorCollector = context.getVarFromParents(SchemaValidationErrorCollector.class); @@ -61,4 +59,14 @@ public TraversalControl visitGraphQLArgument(GraphQLArgument argument, Traverser return TraversalControl.CONTINUE; } + private boolean isDeprecated(GraphQLArgument argument) { + // There can only be at most one @deprecated, because it is not a repeatable directive + GraphQLAppliedDirective deprecatedDirective = argument.getAppliedDirective(Directives.DEPRECATED_DIRECTIVE_DEFINITION.getName()); + if (deprecatedDirective != null) { + return true; + } + // handle code built schemas, where they have no directive but `graphql.schema.GraphQLArgument.Builder#deprecate` has been called directly + return argument.isDeprecated(); + } + } diff --git a/src/test/groovy/graphql/schema/validation/DeprecatedInputObjectAndArgumentsAreValidTest.groovy b/src/test/groovy/graphql/schema/validation/DeprecatedInputObjectAndArgumentsAreValidTest.groovy index 056f134db4..4f82f5f688 100644 --- a/src/test/groovy/graphql/schema/validation/DeprecatedInputObjectAndArgumentsAreValidTest.groovy +++ b/src/test/groovy/graphql/schema/validation/DeprecatedInputObjectAndArgumentsAreValidTest.groovy @@ -1,6 +1,12 @@ package graphql.schema.validation +import graphql.Scalars import graphql.TestUtil +import graphql.schema.GraphQLArgument +import graphql.schema.GraphQLFieldDefinition +import graphql.schema.GraphQLNonNull +import graphql.schema.GraphQLObjectType +import graphql.schema.GraphQLSchema import spock.lang.Specification class DeprecatedInputObjectAndArgumentsAreValidTest extends Specification { @@ -293,4 +299,31 @@ class DeprecatedInputObjectAndArgumentsAreValidTest extends Specification { noExceptionThrown() } + def "schema build via code has the same validation rule"() { + when: + GraphQLArgument deprecatedArg = GraphQLArgument.newArgument() + .name("input") + .type(GraphQLNonNull.nonNull(Scalars.GraphQLString)) + .deprecate("Some very good reason") + .build() + + GraphQLFieldDefinition field = GraphQLFieldDefinition.newFieldDefinition() + .name("field") + .type(Scalars.GraphQLString) + .argument(deprecatedArg) + .build() + + GraphQLObjectType queryType = GraphQLObjectType.newObject() + .name("Query") + .field(field) + .build() + + GraphQLSchema.newSchema() + .query(queryType) + .build() + + then: + def invalidSchemaException = thrown(InvalidSchemaException) + invalidSchemaException.message.contains("Required argument 'input' on field 'field' cannot be deprecated") + } } From dd5bc0309af8d8902de59b4a487bfbd9a0c34f63 Mon Sep 17 00:00:00 2001 From: bbaker Date: Fri, 19 Dec 2025 10:25:21 +1100 Subject: [PATCH 2/2] #4182 - code built schemas should perform deprecated non null field validations as well as SDL built ones --- .../DeprecatedInputObjectAndArgumentsAreValid.java | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/main/java/graphql/schema/validation/DeprecatedInputObjectAndArgumentsAreValid.java b/src/main/java/graphql/schema/validation/DeprecatedInputObjectAndArgumentsAreValid.java index aaeda507a8..f7c1c1c776 100644 --- a/src/main/java/graphql/schema/validation/DeprecatedInputObjectAndArgumentsAreValid.java +++ b/src/main/java/graphql/schema/validation/DeprecatedInputObjectAndArgumentsAreValid.java @@ -42,7 +42,8 @@ public TraversalControl visitGraphQLInputObjectField(GraphQLInputObjectField inp // An applied directive's argument cannot be deprecated. @Override public TraversalControl visitGraphQLArgument(GraphQLArgument argument, TraverserContext context) { - boolean isDeprecated = isDeprecated(argument); + // even if an argument is built using SLD or direct via code, the isDeprecated() method works + boolean isDeprecated = argument.isDeprecated(); if (isDeprecated && GraphQLTypeUtil.isNonNull(argument.getType()) && !argument.hasSetDefaultValue()) { if (context.getParentNode() instanceof GraphQLFieldDefinition) { GraphQLFieldDefinition fieldDefinition = (GraphQLFieldDefinition) context.getParentNode(); @@ -59,14 +60,4 @@ public TraversalControl visitGraphQLArgument(GraphQLArgument argument, Traverser return TraversalControl.CONTINUE; } - private boolean isDeprecated(GraphQLArgument argument) { - // There can only be at most one @deprecated, because it is not a repeatable directive - GraphQLAppliedDirective deprecatedDirective = argument.getAppliedDirective(Directives.DEPRECATED_DIRECTIVE_DEFINITION.getName()); - if (deprecatedDirective != null) { - return true; - } - // handle code built schemas, where they have no directive but `graphql.schema.GraphQLArgument.Builder#deprecate` has been called directly - return argument.isDeprecated(); - } - }