77import graphql .language .ArrayValue ;
88import graphql .language .Directive ;
99import graphql .language .EnumTypeDefinition ;
10+ import graphql .language .EnumTypeExtensionDefinition ;
1011import graphql .language .EnumValue ;
1112import graphql .language .EnumValueDefinition ;
1213import graphql .language .InputObjectTypeDefinition ;
14+ import graphql .language .InputObjectTypeExtensionDefinition ;
1315import graphql .language .InputValueDefinition ;
1416import graphql .language .ListType ;
1517import graphql .language .Node ;
3133import java .util .List ;
3234import java .util .Map ;
3335import java .util .function .Function ;
34- import java .util .stream .Collectors ;
36+ import java .util .stream .Stream ;
3537
3638import static graphql .Assert .assertShouldNeverHappen ;
3739import static graphql .schema .idl .errors .DirectiveIllegalArgumentTypeError .DUPLICATED_KEYS_MESSAGE ;
4446import static graphql .schema .idl .errors .DirectiveIllegalArgumentTypeError .MUST_BE_VALID_ENUM_VALUE_MESSAGE ;
4547import static graphql .schema .idl .errors .DirectiveIllegalArgumentTypeError .NOT_A_VALID_SCALAR_LITERAL_MESSAGE ;
4648import static graphql .schema .idl .errors .DirectiveIllegalArgumentTypeError .UNKNOWN_FIELDS_MESSAGE ;
49+ import static java .util .Collections .emptyList ;
50+ import static java .util .stream .Collectors .counting ;
51+ import static java .util .stream .Collectors .groupingBy ;
52+ import static java .util .stream .Collectors .joining ;
53+ import static java .util .stream .Collectors .toList ;
54+ import static java .util .stream .Collectors .toMap ;
4755
4856/**
4957 * Class to check whether a given directive argument value
5058 * matches a given directive definition.
51- *
5259 */
5360@ Internal
5461class ArgValueOfAllowedTypeChecker {
5562
5663 private static final Logger logNotSafe = LogKit .getNotPrivacySafeLogger (ArgValueOfAllowedTypeChecker .class );
5764
5865 private final Directive directive ;
59- private final Node element ;
66+ private final Node <?> element ;
6067 private final String elementName ;
6168 private final Argument argument ;
6269 private final TypeDefinitionRegistry typeRegistry ;
6370 private final RuntimeWiring runtimeWiring ;
6471
6572 ArgValueOfAllowedTypeChecker (final Directive directive ,
66- final Node element ,
73+ final Node <?> element ,
6774 final String elementName ,
6875 final Argument argument ,
6976 final TypeDefinitionRegistry typeRegistry ,
@@ -79,20 +86,21 @@ class ArgValueOfAllowedTypeChecker {
7986 /**
8087 * Recursively inspects an argument value given an allowed type.
8188 * Given the (invalid) SDL below:
82- *
83- * directive @myDirective(arg: [[String]] ) on FIELD_DEFINITION
84- *
85- * query {
86- * f: String @myDirective(arg: ["A String"])
87- * }
88- *
89+ * <p>
90+ * directive @myDirective(arg: [[String]] ) on FIELD_DEFINITION
91+ * <p>
92+ * query {
93+ * f: String @myDirective(arg: ["A String"])
94+ * }
95+ * <p>
8996 * it will first check that the `myDirective.arg` type is an array
9097 * and fail when finding "A String" as it expected a nested array ([[String]]).
91- * @param errors validation error collector
92- * @param instanceValue directive argument value
98+ *
99+ * @param errors validation error collector
100+ * @param instanceValue directive argument value
93101 * @param allowedArgType directive definition argument allowed type
94102 */
95- void checkArgValueMatchesAllowedType (List <GraphQLError > errors , Value instanceValue , Type allowedArgType ) {
103+ void checkArgValueMatchesAllowedType (List <GraphQLError > errors , Value <?> instanceValue , Type <?> allowedArgType ) {
96104 if (allowedArgType instanceof TypeName ) {
97105 checkArgValueMatchesAllowedTypeName (errors , instanceValue , allowedArgType );
98106 } else if (allowedArgType instanceof ListType ) {
@@ -108,13 +116,13 @@ private void addValidationError(List<GraphQLError> errors, String message, Objec
108116 errors .add (new DirectiveIllegalArgumentTypeError (element , elementName , directive .getName (), argument .getName (), String .format (message , args )));
109117 }
110118
111- private void checkArgValueMatchesAllowedTypeName (List <GraphQLError > errors , Value instanceValue , Type allowedArgType ) {
119+ private void checkArgValueMatchesAllowedTypeName (List <GraphQLError > errors , Value <?> instanceValue , Type <?> allowedArgType ) {
112120 if (instanceValue instanceof NullValue ) {
113121 return ;
114122 }
115123
116124 String allowedTypeName = ((TypeName ) allowedArgType ).getName ();
117- TypeDefinition allowedTypeDefinition = typeRegistry .getType (allowedTypeName )
125+ TypeDefinition <?> allowedTypeDefinition = typeRegistry .getType (allowedTypeName )
118126 .orElseThrow (() -> new AssertException ("Directive unknown argument type '%s'. This should have been validated before." ));
119127
120128 if (allowedTypeDefinition instanceof ScalarTypeDefinition ) {
@@ -128,7 +136,7 @@ private void checkArgValueMatchesAllowedTypeName(List<GraphQLError> errors, Valu
128136 }
129137 }
130138
131- private void checkArgValueMatchesAllowedInputType (List <GraphQLError > errors , Value instanceValue , InputObjectTypeDefinition allowedTypeDefinition ) {
139+ private void checkArgValueMatchesAllowedInputType (List <GraphQLError > errors , Value <?> instanceValue , InputObjectTypeDefinition allowedTypeDefinition ) {
132140 if (!(instanceValue instanceof ObjectValue )) {
133141 addValidationError (errors , EXPECTED_OBJECT_MESSAGE , instanceValue .getClass ().getSimpleName ());
134142 return ;
@@ -139,66 +147,72 @@ private void checkArgValueMatchesAllowedInputType(List<GraphQLError> errors, Val
139147 // then it must be the same type as the definition
140148
141149 List <ObjectField > fields = objectValue .getObjectFields ();
142- List <InputValueDefinition > inputValueDefinitions = allowedTypeDefinition .getInputValueDefinitions ();
150+ List <InputObjectTypeExtensionDefinition > inputObjExt = typeRegistry .inputObjectTypeExtensions ().getOrDefault (allowedTypeDefinition .getName (), emptyList ());
151+ Stream <InputValueDefinition > inputObjExtValues = inputObjExt .stream ().flatMap (inputObj -> inputObj .getInputValueDefinitions ().stream ());
152+ List <InputValueDefinition > inputValueDefinitions = Stream .concat (allowedTypeDefinition .getInputValueDefinitions ().stream (), inputObjExtValues ).collect (toList ());
143153
144154 // check for duplicated fields
145155 Map <String , Long > fieldsToOccurrenceMap = fields .stream ().map (ObjectField ::getName )
146- .collect (Collectors . groupingBy (Function .identity (), Collectors . counting ()));
156+ .collect (groupingBy (Function .identity (), counting ()));
147157
148158 if (fieldsToOccurrenceMap .values ().stream ().anyMatch (count -> count > 1 )) {
149159 addValidationError (errors , DUPLICATED_KEYS_MESSAGE , fieldsToOccurrenceMap .entrySet ().stream ()
150160 .filter (entry -> entry .getValue () > 1 )
151161 .map (Map .Entry ::getKey )
152- .collect (Collectors . joining ("," )));
162+ .collect (joining ("," )));
153163 return ;
154164 }
155165
156166 // check for unknown fields
157167 Map <String , InputValueDefinition > nameToInputValueDefMap = inputValueDefinitions .stream ()
158- .collect (Collectors . toMap (InputValueDefinition ::getName , inputValueDef -> inputValueDef ));
168+ .collect (toMap (InputValueDefinition ::getName , inputValueDef -> inputValueDef ));
159169
160170 List <ObjectField > unknownFields = fields .stream ()
161171 .filter (field -> !nameToInputValueDefMap .containsKey (field .getName ()))
162- .collect (Collectors . toList ());
172+ .collect (toList ());
163173
164174 if (!unknownFields .isEmpty ()) {
165175 addValidationError (errors , UNKNOWN_FIELDS_MESSAGE ,
166176 unknownFields .stream ()
167177 .map (ObjectField ::getName )
168- .collect (Collectors . joining ("," )),
178+ .collect (joining ("," )),
169179 allowedTypeDefinition .getName ());
170180 return ;
171181 }
172182
173183 // fields to map for easy access
174184 Map <String , ObjectField > nameToFieldsMap = fields .stream ()
175- .collect (Collectors . toMap (ObjectField ::getName , objectField -> objectField ));
185+ .collect (toMap (ObjectField ::getName , objectField -> objectField ));
176186 // check each single field with its definition
177187 inputValueDefinitions .forEach (allowedValueDef -> {
178188 ObjectField objectField = nameToFieldsMap .get (allowedValueDef .getName ());
179189 checkArgInputObjectValueFieldMatchesAllowedDefinition (errors , objectField , allowedValueDef );
180190 });
181191 }
182192
183- private void checkArgValueMatchesAllowedEnum (List <GraphQLError > errors , Value instanceValue , EnumTypeDefinition allowedTypeDefinition ) {
193+ private void checkArgValueMatchesAllowedEnum (List <GraphQLError > errors , Value <?> instanceValue , EnumTypeDefinition allowedTypeDefinition ) {
184194 if (!(instanceValue instanceof EnumValue )) {
185195 addValidationError (errors , EXPECTED_ENUM_MESSAGE , instanceValue .getClass ().getSimpleName ());
186196 return ;
187197 }
188198
189199 EnumValue enumValue = ((EnumValue ) instanceValue );
190200
191- boolean noneMatchAllowedEnumValue = allowedTypeDefinition .getEnumValueDefinitions ().stream ()
201+ List <EnumTypeExtensionDefinition > enumExtensions = typeRegistry .enumTypeExtensions ().getOrDefault (allowedTypeDefinition .getName (), emptyList ());
202+ Stream <EnumValueDefinition > enumExtStream = enumExtensions .stream ().flatMap (enumExt -> enumExt .getEnumValueDefinitions ().stream ());
203+ List <EnumValueDefinition > enumValueDefinitions = Stream .concat (allowedTypeDefinition .getEnumValueDefinitions ().stream (), enumExtStream ).collect (toList ());
204+
205+ boolean noneMatchAllowedEnumValue = enumValueDefinitions .stream ()
192206 .noneMatch (enumAllowedValue -> enumAllowedValue .getName ().equals (enumValue .getName ()));
193207
194208 if (noneMatchAllowedEnumValue ) {
195- addValidationError (errors , MUST_BE_VALID_ENUM_VALUE_MESSAGE , enumValue .getName (), allowedTypeDefinition . getEnumValueDefinitions () .stream ()
196- .map (EnumValueDefinition ::getName )
197- .collect (Collectors . joining ("," )));
209+ addValidationError (errors , MUST_BE_VALID_ENUM_VALUE_MESSAGE , enumValue .getName (), enumValueDefinitions .stream ()
210+ .map (EnumValueDefinition ::getName )
211+ .collect (joining ("," )));
198212 }
199213 }
200214
201- private void checkArgValueMatchesAllowedScalar (List <GraphQLError > errors , Value instanceValue , String allowedTypeName ) {
215+ private void checkArgValueMatchesAllowedScalar (List <GraphQLError > errors , Value <?> instanceValue , String allowedTypeName ) {
202216 if (instanceValue instanceof ArrayValue
203217 || instanceValue instanceof EnumValue
204218 || instanceValue instanceof ObjectValue ) {
@@ -231,23 +245,22 @@ private void checkArgInputObjectValueFieldMatchesAllowedDefinition(List<GraphQLE
231245 // - field definition is nullable hence null can be used
232246 }
233247
234- private void checkArgValueMatchesAllowedNonNullType (List <GraphQLError > errors , Value instanceValue , NonNullType allowedArgType ) {
248+ private void checkArgValueMatchesAllowedNonNullType (List <GraphQLError > errors , Value <?> instanceValue , NonNullType allowedArgType ) {
235249 if (instanceValue instanceof NullValue ) {
236250 addValidationError (errors , EXPECTED_NON_NULL_MESSAGE );
237251 return ;
238252 }
239253
240- Type unwrappedAllowedType = allowedArgType .getType ();
254+ Type <?> unwrappedAllowedType = allowedArgType .getType ();
241255 checkArgValueMatchesAllowedType (errors , instanceValue , unwrappedAllowedType );
242256 }
243257
244- private void checkArgValueMatchesAllowedListType (List <GraphQLError > errors , Value instanceValue , ListType allowedArgType ) {
258+ private void checkArgValueMatchesAllowedListType (List <GraphQLError > errors , Value <?> instanceValue , ListType allowedArgType ) {
245259 if (instanceValue instanceof NullValue ) {
246260 return ;
247261 }
248262
249-
250- Type unwrappedAllowedType = allowedArgType .getType ();
263+ Type <?> unwrappedAllowedType = allowedArgType .getType ();
251264 if (!(instanceValue instanceof ArrayValue )) {
252265 checkArgValueMatchesAllowedType (errors , instanceValue , unwrappedAllowedType );
253266 return ;
@@ -259,14 +272,14 @@ private void checkArgValueMatchesAllowedListType(List<GraphQLError> errors, Valu
259272 // validate each instance value in the list, all instances must match for the list to match
260273 arrayValue .getValues ().forEach (value -> {
261274 // restrictive check for sub-arrays
262- if (isUnwrappedList && ! (value instanceof ArrayValue )) {
275+ if (isUnwrappedList && !(value instanceof ArrayValue )) {
263276 addValidationError (errors , EXPECTED_LIST_MESSAGE , value .getClass ().getSimpleName ());
264277 }
265278 checkArgValueMatchesAllowedType (errors , value , unwrappedAllowedType );
266279 });
267280 }
268281
269- private boolean isArgumentValueScalarLiteral (GraphQLScalarType scalarType , Value instanceValue ) {
282+ private boolean isArgumentValueScalarLiteral (GraphQLScalarType scalarType , Value <?> instanceValue ) {
270283 try {
271284 scalarType .getCoercing ().parseLiteral (instanceValue );
272285 return true ;
0 commit comments