@@ -302,20 +302,43 @@ public static Initializer initializer() {
302
302
public interface Initializer {
303
303
304
304
/**
305
- * Provide a function to derive the simple class name that corresponds to a
306
- * GraphQL union member type, or a GraphQL interface implementation type.
307
- * This is then used to find a Java class in the same package as that of
308
- * the return type of the controller method for the interface or union.
309
- * <p>The default, {@link GraphQLObjectType#getName()} is used
305
+ * Provide an explicit mapping between a GraphQL type name and the Java
306
+ * class(es) that represent it at runtime to help inspect union member
307
+ * and interface implementation types when those associations cannot be
308
+ * discovered otherwise.
309
+ * <p>Out of the box, there a several ways through which schema inspection
310
+ * can locate such types automatically:
311
+ * <ul>
312
+ * <li>Java class representations are located in the same package as the
313
+ * type returned from the controller method for a union or interface field,
314
+ * and their {@link Class#getSimpleName() simple class names} match GraphQL
315
+ * type names, possibly with the help of a {@link #classNameFunction}.
316
+ * <li>Java class representations are located in the same package as the
317
+ * declaring class of the controller method for a union or interface field.
318
+ * <li>Controller methods return the Java class representations of schema
319
+ * fields for concrete union member or interface implementation types.
320
+ * </ul>
321
+ * @param graphQlTypeName the name of a GraphQL Object type
322
+ * @param aClass one or more Java class representations
323
+ * @return the same initializer instance
324
+ */
325
+ Initializer classMapping (String graphQlTypeName , Class <?>... aClass );
326
+
327
+ /**
328
+ * Help to derive the {@link Class#getSimpleName() simple class name} for
329
+ * the Java representation of a GraphQL union member or interface implementing
330
+ * type. For more details, see {@link #classMapping(String, Class[])}.
331
+ * <p>By default, {@link GraphQLObjectType#getName()} is used.
310
332
* @param function the function to use
311
333
* @return the same initializer instance
312
334
*/
313
335
Initializer classNameFunction (Function <GraphQLObjectType , String > function );
314
336
315
337
/**
316
- * Add a custom {@link ClassResolver} to use to find the Java class for a
317
- * GraphQL union member type, or a GraphQL interface implementation type.
318
- * @param resolver the resolver to add
338
+ * Alternative to {@link #classMapping(String, Class[])} with a custom
339
+ * {@link ClassResolver} to find the Java class(es) for a GraphQL union
340
+ * member or interface implementation type.
341
+ * @param resolver the resolver to use to find associated Java classes
319
342
* @return the same initializer instance
320
343
*/
321
344
Initializer classResolver (ClassResolver resolver );
@@ -345,14 +368,6 @@ public interface ClassResolver {
345
368
*/
346
369
List <Class <?>> resolveClass (GraphQLObjectType objectType , GraphQLNamedOutputType interfaceOrUnionType );
347
370
348
-
349
- /**
350
- * Create a resolver from the given mappings.
351
- * @param mappings from Class to GraphQL type name
352
- */
353
- static ClassResolver create (Map <Class <?>, String > mappings ) {
354
- return new MappingClassResolver (mappings );
355
- }
356
371
}
357
372
358
373
@@ -365,6 +380,8 @@ private static final class DefaultInitializer implements Initializer {
365
380
366
381
private final List <ClassResolver > classResolvers = new ArrayList <>();
367
382
383
+ private final MultiValueMap <String , Class <?>> classMappings = new LinkedMultiValueMap <>();
384
+
368
385
@ Override
369
386
public Initializer classNameFunction (Function <GraphQLObjectType , String > function ) {
370
387
this .classNameFunction = function ;
@@ -378,13 +395,19 @@ public Initializer classResolver(ClassResolver resolver) {
378
395
}
379
396
380
397
@ Override
381
- public SchemaReport inspect (GraphQLSchema schema , Map <String , Map <String , DataFetcher >> fetchers ) {
398
+ public Initializer classMapping (String graphQlTypeName , Class <?>... classes ) {
399
+ for (Class <?> aClass : classes ) {
400
+ this .classMappings .add (graphQlTypeName , aClass );
401
+ }
402
+ return this ;
403
+ }
382
404
383
- ReflectionClassResolver reflectionResolver =
384
- ReflectionClassResolver . create ( schema , fetchers , this . classNameFunction );
405
+ @ Override
406
+ public SchemaReport inspect ( GraphQLSchema schema , Map < String , Map < String , DataFetcher >> fetchers ) {
385
407
386
408
List <ClassResolver > resolvers = new ArrayList <>(this .classResolvers );
387
- resolvers .add (reflectionResolver );
409
+ resolvers .add (new MappingClassResolver (this .classMappings ));
410
+ resolvers .add (ReflectionClassResolver .create (schema , fetchers , this .classNameFunction ));
388
411
389
412
InterfaceUnionLookup lookup = InterfaceUnionLookup .create (schema , resolvers );
390
413
@@ -399,15 +422,15 @@ public SchemaReport inspect(GraphQLSchema schema, Map<String, Map<String, DataFe
399
422
*/
400
423
private static final class MappingClassResolver implements ClassResolver {
401
424
402
- private final MultiValueMap <String , Class <?>> map = new LinkedMultiValueMap <>();
425
+ private final MultiValueMap <String , Class <?>> mappings = new LinkedMultiValueMap <>();
403
426
404
- MappingClassResolver (Map < Class <?>, String > mappings ) {
405
- mappings . forEach (( key , value ) -> this .map . add ( value , key ) );
427
+ MappingClassResolver (MultiValueMap < String , Class <?>> mappings ) {
428
+ this .mappings . putAll ( mappings );
406
429
}
407
430
408
431
@ Override
409
432
public List <Class <?>> resolveClass (GraphQLObjectType objectType , GraphQLNamedOutputType interfaceOrUnionType ) {
410
- return this .map .getOrDefault (objectType .getName (), Collections .emptyList ());
433
+ return this .mappings .getOrDefault (objectType .getName (), Collections .emptyList ());
411
434
}
412
435
}
413
436
@@ -478,7 +501,7 @@ public static ReflectionClassResolver create(
478
501
if (PACKAGE_PREDICATE .test (clazz .getPackageName ())) {
479
502
addClassPrefix (outputTypeName , clazz , classPrefixes );
480
503
}
481
- else if (dataFetcher instanceof SelfDescribingDataFetcher <?> selfDescribing ) {
504
+ if (dataFetcher instanceof SelfDescribingDataFetcher <?> selfDescribing ) {
482
505
if (selfDescribing .getReturnType ().getSource () instanceof MethodParameter param ) {
483
506
addClassPrefix (outputTypeName , param .getDeclaringClass (), classPrefixes );
484
507
}
0 commit comments