22
22
import org .junit .jupiter .api .Nested ;
23
23
import org .junit .jupiter .api .Test ;
24
24
25
+ import org .springframework .graphql .data .method .annotation .Argument ;
25
26
import org .springframework .graphql .data .method .annotation .QueryMapping ;
26
27
import org .springframework .graphql .execution .SchemaMappingInspector .ClassResolver ;
27
28
import org .springframework .stereotype .Controller ;
@@ -35,16 +36,20 @@ public class SchemaMappingInspectorUnionTests extends SchemaMappingInspectorTest
35
36
36
37
private static final String schema = """
37
38
type Query {
38
- search: [SearchResult!]!
39
+ search: [SearchResult]
40
+ article(id: ID): Article
39
41
}
40
- union SearchResult = Photo | Video
42
+ union SearchResult = Article | Photo | Video
41
43
type Photo {
42
44
height: Int
43
45
width: Int
44
46
}
45
47
type Video {
46
48
title: String
47
49
}
50
+ type Article {
51
+ content: String
52
+ }
48
53
""" ;
49
54
50
55
@@ -55,8 +60,10 @@ class UnmappedFields {
55
60
void reportUnmappedFieldsByCheckingReturnTypePackage () {
56
61
SchemaReport report = inspectSchema (schema , SearchController .class );
57
62
assertThatReport (report )
58
- .hasSkippedTypeCount (0 )
59
- .hasUnmappedFieldCount (3 )
63
+ .hasSkippedTypeCount (1 )
64
+ .containsSkippedTypes ("Article" )
65
+ .hasUnmappedFieldCount (4 )
66
+ .containsUnmappedFields ("Query" , "article" )
60
67
.containsUnmappedFields ("Photo" , "height" , "width" )
61
68
.containsUnmappedFields ("Video" , "title" );
62
69
}
@@ -65,17 +72,20 @@ void reportUnmappedFieldsByCheckingReturnTypePackage() {
65
72
void reportUnmappedFieldsByCheckingControllerTypePackage () {
66
73
SchemaReport report = inspectSchema (schema , ObjectSearchController .class );
67
74
assertThatReport (report )
68
- .hasSkippedTypeCount (0 )
69
- .hasUnmappedFieldCount (3 )
75
+ .hasSkippedTypeCount (1 )
76
+ .containsSkippedTypes ("Article" )
77
+ .hasUnmappedFieldCount (4 )
78
+ .containsUnmappedFields ("Query" , "article" )
70
79
.containsUnmappedFields ("Photo" , "height" , "width" )
71
80
.containsUnmappedFields ("Video" , "title" );
72
81
}
73
82
74
83
75
- sealed interface ResultItem permits Photo , Video { }
76
84
record Photo () implements ResultItem { }
77
85
record Video () implements ResultItem { }
78
86
87
+ sealed interface ResultItem permits Photo , Video { }
88
+
79
89
@ Controller
80
90
static class SearchController {
81
91
@@ -108,8 +118,10 @@ void classNameFunction() {
108
118
SearchController .class );
109
119
110
120
assertThatReport (report )
111
- .hasSkippedTypeCount (0 )
112
- .hasUnmappedFieldCount (3 )
121
+ .hasSkippedTypeCount (1 )
122
+ .containsSkippedTypes ("Article" )
123
+ .hasUnmappedFieldCount (4 )
124
+ .containsUnmappedFields ("Query" , "article" )
113
125
.containsUnmappedFields ("Photo" , "height" , "width" )
114
126
.containsUnmappedFields ("Video" , "title" );
115
127
}
@@ -124,8 +136,11 @@ void classNameTypeResolver() {
124
136
SearchController .class );
125
137
126
138
assertThatReport (report )
127
- .hasUnmappedFieldCount (2 ).containsUnmappedFields ("Photo" , "height" , "width" )
128
- .hasSkippedTypeCount (1 ).containsSkippedTypes ("Video" );
139
+ .hasSkippedTypeCount (2 )
140
+ .containsSkippedTypes ("Article" , "Video" )
141
+ .hasUnmappedFieldCount (3 )
142
+ .containsUnmappedFields ("Query" , "article" )
143
+ .containsUnmappedFields ("Photo" , "height" , "width" );
129
144
}
130
145
131
146
sealed interface ResultItem permits PhotoImpl , VideoImpl { }
@@ -149,7 +164,7 @@ class SkippedTypes {
149
164
@ Test
150
165
void reportSkippedImplementations () {
151
166
SchemaReport report = inspectSchema (schema , SearchController .class );
152
- assertThatReport (report ).hasSkippedTypeCount (2 ).containsSkippedTypes ("Photo" , "Video" );
167
+ assertThatReport (report ).hasSkippedTypeCount (3 ).containsSkippedTypes ("Article" , "Photo" , "Video" );
153
168
}
154
169
155
170
interface ResultItem { }
@@ -164,4 +179,38 @@ List<ResultItem> search() {
164
179
}
165
180
}
166
181
182
+
183
+ @ Nested
184
+ class CandidateSkippedTypes {
185
+
186
+ // A union member type is only a candidate to be skipped until the inspection is done.
187
+ // Use of the concrete type elsewhere may provide more information.
188
+
189
+ @ Test
190
+ void candidateNotSkippedIfConcreteUseElsewhere () {
191
+ SchemaReport report = inspectSchema (schema , SearchController .class );
192
+ assertThatReport (report ).hasSkippedTypeCount (2 ).containsSkippedTypes ("Photo" , "Video" );
193
+ }
194
+
195
+ @ Controller
196
+ static class SearchController {
197
+
198
+ @ QueryMapping
199
+ List <Object > search () {
200
+ throw new UnsupportedOperationException ();
201
+ }
202
+
203
+ @ QueryMapping
204
+ Article article (@ Argument Long id ) {
205
+ throw new UnsupportedOperationException ();
206
+ }
207
+ }
208
+ }
209
+
210
+
211
+ /**
212
+ * Declared outside {@link CandidateSkippedTypes}, so the union lookup won't find it.
213
+ */
214
+ private record Article (String content ) { }
215
+
167
216
}
0 commit comments