@@ -64,124 +64,139 @@ class SchemaMappingInspector {
6464
6565 private static final Log logger = LogFactory .getLog (SchemaMappingInspector .class );
6666
67- Report inspectSchemaMappings (GraphQLSchema schema , RuntimeWiring runtimeWiring ) {
68- ReportBuilder report = ReportBuilder .create ();
69- SchemaMappingInspection inspection = new SchemaMappingInspection (runtimeWiring );
70- inspection .inspectOperation (schema .getQueryType (), report );
71- inspection .inspectOperation (schema .getMutationType (), report );
72- inspection .inspectOperation (schema .getSubscriptionType (), report );
73- return report .build ();
74- }
7567
76- private static class SchemaMappingInspection {
68+ private final GraphQLSchema schema ;
7769
78- private final RuntimeWiring runtimeWiring ;
70+ private final RuntimeWiring runtimeWiring ;
7971
80- private final Set <String > seenTypes = new HashSet <>();
72+ private final Set <String > seenTypes = new HashSet <>();
8173
82- SchemaMappingInspection (RuntimeWiring runtimeWiring ) {
83- this .runtimeWiring = runtimeWiring ;
84- }
8574
86- @ SuppressWarnings ("rawtypes" )
87- void inspectOperation (@ Nullable GraphQLObjectType operationType , ReportBuilder report ) {
88- if (operationType != null ) {
89- Map <String , DataFetcher > operationDataFetchers = this .runtimeWiring .getDataFetcherForType (operationType .getName ());
90- for (GraphQLFieldDefinition fieldDefinition : operationType .getFieldDefinitions ()) {
91- if (operationDataFetchers .containsKey (fieldDefinition .getName ())) {
92- DataFetcher fieldDataFetcher = operationDataFetchers .get (fieldDefinition .getName ());
93- if (fieldDataFetcher instanceof SelfDescribingDataFetcher <?> selfDescribingDataFetcher ) {
94- inspectType (fieldDefinition .getType (), selfDescribingDataFetcher .getReturnType (), report );
95- }
96- }
97- else {
98- report .missingOperation (operationType , fieldDefinition );
75+ private SchemaMappingInspector (GraphQLSchema schema , RuntimeWiring runtimeWiring ) {
76+ this .schema = schema ;
77+ this .runtimeWiring = runtimeWiring ;
78+ }
79+
80+
81+ public Report inspectMappings () {
82+ ReportBuilder report = ReportBuilder .create ();
83+ inspectOperation (schema .getQueryType (), report );
84+ inspectOperation (schema .getMutationType (), report );
85+ inspectOperation (schema .getSubscriptionType (), report );
86+ return report .build ();
87+ }
88+
89+
90+ @ SuppressWarnings ("rawtypes" )
91+ private void inspectOperation (@ Nullable GraphQLObjectType operationType , ReportBuilder report ) {
92+ if (operationType != null ) {
93+ Map <String , DataFetcher > operationDataFetchers = this .runtimeWiring .getDataFetcherForType (operationType .getName ());
94+ for (GraphQLFieldDefinition fieldDefinition : operationType .getFieldDefinitions ()) {
95+ if (operationDataFetchers .containsKey (fieldDefinition .getName ())) {
96+ DataFetcher fieldDataFetcher = operationDataFetchers .get (fieldDefinition .getName ());
97+ if (fieldDataFetcher instanceof SelfDescribingDataFetcher <?> selfDescribingDataFetcher ) {
98+ inspectType (fieldDefinition .getType (), selfDescribingDataFetcher .getReturnType (), report );
9999 }
100100 }
101+ else {
102+ report .missingOperation (operationType , fieldDefinition );
103+ }
101104 }
102105 }
106+ }
103107
104- private void inspectType (GraphQLType type , ResolvableType declaredType , ReportBuilder report ) {
105- if (type instanceof GraphQLObjectType objectType ) {
106- inspectObjectType (objectType , declaredType , report );
107- }
108- else if (type instanceof GraphQLList listType ) {
109- inspectType (listType .getWrappedType (), declaredType .getNested (2 ), report );
110- }
111- else if (type instanceof GraphQLNonNull nonNullType ) {
112- inspectType (nonNullType .getWrappedType (), declaredType , report );
113- }
114- else if (type instanceof GraphQLNamedType namedType && logger .isTraceEnabled ()){
115- logger .trace ("Cannot inspect type '" + namedType .getName () + "', inspector does not support "
116- + type .getClass ().getSimpleName ());
117- }
108+ private void inspectType (GraphQLType type , ResolvableType declaredType , ReportBuilder report ) {
109+ if (type instanceof GraphQLObjectType objectType ) {
110+ inspectObjectType (objectType , declaredType , report );
111+ }
112+ else if (type instanceof GraphQLList listType ) {
113+ inspectType (listType .getWrappedType (), declaredType .getNested (2 ), report );
118114 }
115+ else if (type instanceof GraphQLNonNull nonNullType ) {
116+ inspectType (nonNullType .getWrappedType (), declaredType , report );
117+ }
118+ else if (type instanceof GraphQLNamedType namedType && logger .isTraceEnabled ()){
119+ logger .trace ("Cannot inspect type '" + namedType .getName () + "', inspector does not support "
120+ + type .getClass ().getSimpleName ());
121+ }
122+ }
119123
120- @ SuppressWarnings ("rawtypes" )
121- private void inspectObjectType (GraphQLObjectType objectType , ResolvableType declaredType , ReportBuilder report ) {
122- if (isTypeAlreadyInspected (objectType )) {
123- return ;
124- }
125- if (isConnectionType (objectType )) {
126- objectType = getEdgeNodeType (objectType );
127- declaredType = declaredType .getNested (2 );
124+ @ SuppressWarnings ("rawtypes" )
125+ private void inspectObjectType (GraphQLObjectType objectType , ResolvableType declaredType , ReportBuilder report ) {
126+ if (isTypeAlreadyInspected (objectType )) {
127+ return ;
128+ }
129+ if (isConnectionType (objectType )) {
130+ objectType = getEdgeNodeType (objectType );
131+ declaredType = declaredType .getNested (2 );
132+ }
133+ Map <String , DataFetcher > typeDataFetcher = this .runtimeWiring .getDataFetcherForType (objectType .getName ());
134+ Class <?> declaredClass = unwrapPublisherTypes (declaredType );
135+ for (GraphQLFieldDefinition field : objectType .getFieldDefinitions ()) {
136+ if (typeDataFetcher .containsKey (field .getName ())) {
137+ DataFetcher fieldDataFetcher = typeDataFetcher .get (field .getName ());
138+ if (fieldDataFetcher instanceof SelfDescribingDataFetcher <?> typedFieldDataFetcher ) {
139+ inspectType (field .getType (), typedFieldDataFetcher .getReturnType (), report );
140+ }
128141 }
129- Map <String , DataFetcher > typeDataFetcher = this .runtimeWiring .getDataFetcherForType (objectType .getName ());
130- Class <?> declaredClass = unwrapPublisherTypes (declaredType );
131- for (GraphQLFieldDefinition field : objectType .getFieldDefinitions ()) {
132- if (typeDataFetcher .containsKey (field .getName ())) {
133- DataFetcher fieldDataFetcher = typeDataFetcher .get (field .getName ());
134- if (fieldDataFetcher instanceof SelfDescribingDataFetcher <?> typedFieldDataFetcher ) {
135- inspectType (field .getType (), typedFieldDataFetcher .getReturnType (), report );
142+ else {
143+ try {
144+ if (declaredClass == null || BeanUtils .getPropertyDescriptor (declaredClass , field .getName ()) == null ) {
145+ report .missingField (objectType , field );
136146 }
137147 }
138- else {
139- try {
140- if (declaredClass == null || BeanUtils .getPropertyDescriptor (declaredClass , field .getName ()) == null ) {
141- report .missingField (objectType , field );
142- }
143- }
144- catch (BeansException exc ) {
145- logger .debug ("Failed while inspecting " + declaredType + " for property " + field .getName () + "" , exc );
146- }
148+ catch (BeansException exc ) {
149+ logger .debug ("Failed while inspecting " + declaredType + " for property " + field .getName () + "" , exc );
147150 }
148151 }
149152 }
153+ }
150154
151- private boolean isConnectionType (GraphQLObjectType objectType ) {
152- return (objectType .getName ().endsWith ("Connection" ) &&
153- objectType .getField ("edges" ) != null && objectType .getField ("pageInfo" ) != null );
154- }
155+ private boolean isConnectionType (GraphQLObjectType objectType ) {
156+ return (objectType .getName ().endsWith ("Connection" ) &&
157+ objectType .getField ("edges" ) != null && objectType .getField ("pageInfo" ) != null );
158+ }
155159
156- @ NotNull
157- private GraphQLObjectType getEdgeNodeType (GraphQLObjectType objectType ) {
158- GraphQLList edgesListType = (GraphQLList ) unwrapNonNull (objectType .getField ("edges" ).getType ());
159- GraphQLObjectType edgeType = (GraphQLObjectType ) edgesListType .getWrappedType ();
160- return (GraphQLObjectType ) unwrapNonNull (edgeType .getField ("node" ).getType ());
161- }
160+ @ NotNull
161+ private GraphQLObjectType getEdgeNodeType (GraphQLObjectType objectType ) {
162+ GraphQLList edgesListType = (GraphQLList ) unwrapNonNull (objectType .getField ("edges" ).getType ());
163+ GraphQLObjectType edgeType = (GraphQLObjectType ) edgesListType .getWrappedType ();
164+ return (GraphQLObjectType ) unwrapNonNull (edgeType .getField ("node" ).getType ());
165+ }
162166
163- private <T extends GraphQLType > GraphQLType unwrapNonNull (GraphQLType outputType ) {
164- return (outputType instanceof GraphQLNonNull wrapper ? wrapper .getWrappedType () : outputType );
165- }
167+ private <T extends GraphQLType > GraphQLType unwrapNonNull (GraphQLType outputType ) {
168+ return (outputType instanceof GraphQLNonNull wrapper ? wrapper .getWrappedType () : outputType );
169+ }
166170
167- @ Nullable
168- private Class <?> unwrapPublisherTypes (ResolvableType declaredType ) {
169- Class <?> rawClass = declaredType .getRawClass ();
170- if (rawClass != null ) {
171- ReactiveAdapter adapter = ReactiveAdapterRegistry .getSharedInstance ().getAdapter (declaredType .getRawClass ());
172- if (adapter != null ) {
173- return declaredType .getNested (2 ).getRawClass ();
174- }
171+ @ Nullable
172+ private Class <?> unwrapPublisherTypes (ResolvableType declaredType ) {
173+ Class <?> rawClass = declaredType .getRawClass ();
174+ if (rawClass != null ) {
175+ ReactiveAdapter adapter = ReactiveAdapterRegistry .getSharedInstance ().getAdapter (declaredType .getRawClass ());
176+ if (adapter != null ) {
177+ return declaredType .getNested (2 ).getRawClass ();
175178 }
176- return rawClass ;
177179 }
180+ return rawClass ;
181+ }
182+
183+ private boolean isTypeAlreadyInspected (GraphQLObjectType objectType ) {
184+ return !this .seenTypes .add (objectType .getName ());
185+ }
178186
179- private boolean isTypeAlreadyInspected (GraphQLObjectType objectType ) {
180- return !this .seenTypes .add (objectType .getName ());
181- }
182187
188+ /**
189+ * Inspect the schema mappings and produce a report.
190+ * @param schema the schema to inspect
191+ * @param runtimeWiring for {@code DataFetcher} mappings
192+ * @return the resulting report
193+ */
194+ public static Report inspect (GraphQLSchema schema , RuntimeWiring runtimeWiring ) {
195+ return new SchemaMappingInspector (schema , runtimeWiring ).inspectMappings ();
183196 }
184197
198+
199+
185200 record Report (MultiValueMap <String , String > missingOperations , MultiValueMap <String , String > missingFields ) {
186201
187202 String getSummary () {
@@ -190,7 +205,7 @@ String getSummary() {
190205 builder .append ("no missing mapping." );
191206 }
192207 else {
193- builder .append (getDetailedReport ());
208+ builder .append (getDetailedReport ());
194209 }
195210 return builder .toString ();
196211 }
@@ -210,6 +225,7 @@ boolean isEmpty() {
210225
211226 }
212227
228+
213229 private static class ReportBuilder {
214230
215231 private final MultiValueMap <String , String > missingOperations = new LinkedMultiValueMap <>();
0 commit comments