Skip to content

Commit cf1e838

Browse files
authored
Merge pull request graphql-java#1450 from tinnou/9.x-fix-classCastException-type-condition-input-type
Fix graphql-java#1440 ClassCastException when using a fragment with wrong input type condition and overlapping fields are being merged.
2 parents 65dea85 + 78d7b15 commit cf1e838

File tree

4 files changed

+94
-4
lines changed

4 files changed

+94
-4
lines changed

src/main/java/graphql/validation/rules/FragmentsOnCompositeType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public void checkFragmentDefinition(FragmentDefinition fragmentDefinition) {
3636
if (type == null) return;
3737
if (!(type instanceof GraphQLCompositeType)) {
3838
String message = "Fragment type condition is invalid, must be on Object/Interface/Union";
39-
addError(ValidationErrorType.InlineFragmentTypeConditionInvalid, fragmentDefinition.getSourceLocation(), message);
39+
addError(ValidationErrorType.FragmentTypeConditionInvalid, fragmentDefinition.getSourceLocation(), message);
4040
}
4141
}
4242
}

src/main/java/graphql/validation/rules/OverlappingFieldsCanBeMerged.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,14 +305,14 @@ private void collectFieldsForFragmentSpread(Map<String, List<FieldAndType>> fiel
305305
return;
306306
}
307307
visitedFragmentSpreads.add(fragment.getName());
308-
GraphQLOutputType graphQLType = (GraphQLOutputType) TypeFromAST.getTypeFromAST(getValidationContext().getSchema(),
308+
GraphQLType graphQLType = TypeFromAST.getTypeFromAST(getValidationContext().getSchema(),
309309
fragment.getTypeCondition());
310310
collectFields(fieldMap, fragment.getSelectionSet(), graphQLType, visitedFragmentSpreads);
311311
}
312312

313313
private void collectFieldsForInlineFragment(Map<String, List<FieldAndType>> fieldMap, Set<String> visitedFragmentSpreads, GraphQLType parentType, InlineFragment inlineFragment) {
314314
GraphQLType graphQLType = inlineFragment.getTypeCondition() != null
315-
? (GraphQLOutputType) TypeFromAST.getTypeFromAST(getValidationContext().getSchema(), inlineFragment.getTypeCondition())
315+
? TypeFromAST.getTypeFromAST(getValidationContext().getSchema(), inlineFragment.getTypeCondition())
316316
: parentType;
317317
collectFields(fieldMap, inlineFragment.getSelectionSet(), graphQLType, visitedFragmentSpreads);
318318
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package graphql
2+
3+
import graphql.validation.ValidationError
4+
import graphql.validation.ValidationErrorType
5+
import spock.lang.Specification
6+
7+
class Issue1440 extends Specification {
8+
9+
def schema = TestUtil.schema("""
10+
type Query {
11+
nothing: String
12+
}
13+
14+
type Mutation {
15+
updateUDI(input: UDIInput!): UDIOutput
16+
}
17+
18+
type UDIOutput {
19+
device: String
20+
version: String
21+
}
22+
23+
input UDIInput {
24+
device: String
25+
version: String
26+
}
27+
""")
28+
29+
def graphQL = GraphQL.newGraphQL(schema).build()
30+
31+
32+
def "#1440 when fragment type condition is input type it should return validation error - not classCastException"() {
33+
when:
34+
def executionInput = ExecutionInput.newExecutionInput()
35+
.query('''
36+
mutation UpdateUDI($input: UDIInput!) {
37+
updateUDI(input: $input) {
38+
...fragOnInputType
39+
__typename
40+
}
41+
}
42+
43+
# fragment should only target composite types
44+
fragment fragOnInputType on UDIInput {
45+
device
46+
version
47+
__typename
48+
}
49+
50+
''')
51+
.variables([input: [device: 'device', version: 'version'] ])
52+
.build()
53+
54+
def executionResult = graphQL.execute(executionInput)
55+
56+
then:
57+
58+
executionResult.data == null
59+
executionResult.errors.size() == 1
60+
(executionResult.errors[0] as ValidationError).validationErrorType == ValidationErrorType.FragmentTypeConditionInvalid
61+
}
62+
63+
def "#1440 when inline fragment type condition is input type it should return validation error - not classCastException"() {
64+
when:
65+
def executionInput = ExecutionInput.newExecutionInput()
66+
.query('''
67+
mutation UpdateUDI($input: UDIInput!) {
68+
updateUDI(input: $input) {
69+
# fragment should only target composite types
70+
... on UDIInput {
71+
device
72+
version
73+
__typename
74+
}
75+
__typename
76+
}
77+
}
78+
''')
79+
.variables([input: [device: 'device', version: 'version'] ])
80+
.build()
81+
82+
def executionResult = graphQL.execute(executionInput)
83+
84+
then:
85+
86+
executionResult.data == null
87+
executionResult.errors.size() == 1
88+
(executionResult.errors[0] as ValidationError).validationErrorType == ValidationErrorType.InlineFragmentTypeConditionInvalid
89+
}
90+
}

src/test/groovy/graphql/validation/rules/FragmentsOnCompositeTypeTest.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class FragmentsOnCompositeTypeTest extends Specification {
6868
fragmentsOnCompositeType.checkFragmentDefinition(fragmentDefinition)
6969

7070
then:
71-
errorCollector.containsValidationError(ValidationErrorType.InlineFragmentTypeConditionInvalid)
71+
errorCollector.containsValidationError(ValidationErrorType.FragmentTypeConditionInvalid)
7272
}
7373

7474

0 commit comments

Comments
 (0)