Skip to content

Commit 816c202

Browse files
committed
Refactoring in SchemaMappingInspector
Functionally neutral refactoring. Consolidate logic to initialize union/interface metadata, better encapsulation, and readability.
1 parent 79854ec commit 816c202

File tree

1 file changed

+99
-81
lines changed

1 file changed

+99
-81
lines changed

spring-graphql/src/main/java/org/springframework/graphql/execution/SchemaMappingInspector.java

+99-81
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,15 @@ public final class SchemaMappingInspector {
9898

9999
private SchemaMappingInspector(
100100
GraphQLSchema schema, Map<String, Map<String, DataFetcher>> dataFetchers,
101-
List<ClassResolver> classResolvers, Function<GraphQLObjectType, String> classNameFunction) {
101+
InterfaceUnionLookup interfaceUnionLookup) {
102102

103103
Assert.notNull(schema, "GraphQLSchema is required");
104104
Assert.notNull(dataFetchers, "DataFetcher map is required");
105+
Assert.notNull(interfaceUnionLookup, "InterfaceUnionLookup is required");
106+
105107
this.schema = schema;
106108
this.dataFetchers = dataFetchers;
107-
this.interfaceUnionLookup = new InterfaceUnionLookup(schema, dataFetchers, classResolvers, classNameFunction);
109+
this.interfaceUnionLookup = interfaceUnionLookup;
108110
}
109111

110112

@@ -374,16 +376,12 @@ static ClassResolver create(Map<Class<?>, String> mappings) {
374376
/**
375377
* Default implementation of {@link Initializer}.
376378
*/
377-
private static class DefaultInitializer implements Initializer {
379+
private static final class DefaultInitializer implements Initializer {
378380

379381
private Function<GraphQLObjectType, String> classNameFunction = GraphQLObjectType::getName;
380382

381383
private final List<ClassResolver> classResolvers = new ArrayList<>();
382384

383-
DefaultInitializer() {
384-
this.classResolvers.add((objectType, interfaceOrUnionType) -> Collections.emptyList());
385-
}
386-
387385
@Override
388386
public Initializer classNameFunction(Function<GraphQLObjectType, String> function) {
389387
this.classNameFunction = function;
@@ -398,8 +396,17 @@ public Initializer classResolver(ClassResolver resolver) {
398396

399397
@Override
400398
public SchemaReport inspect(GraphQLSchema schema, Map<String, Map<String, DataFetcher>> fetchers) {
401-
return new SchemaMappingInspector(
402-
schema, fetchers, this.classResolvers, this.classNameFunction).getOrCreateReport();
399+
400+
ReflectionClassResolver reflectionResolver =
401+
ReflectionClassResolver.create(schema, fetchers, this.classNameFunction);
402+
403+
List<ClassResolver> resolvers = new ArrayList<>(this.classResolvers);
404+
resolvers.add(reflectionResolver);
405+
406+
InterfaceUnionLookup lookup = InterfaceUnionLookup.create(schema, resolvers);
407+
408+
SchemaMappingInspector inspector = new SchemaMappingInspector(schema, fetchers, lookup);
409+
return inspector.getOrCreateReport();
403410
}
404411
}
405412

@@ -427,18 +434,19 @@ public List<Class<?>> resolveClass(GraphQLObjectType objectType, GraphQLNamedOut
427434
* the GraphQL object type, and then prepends a prefixes such as a package
428435
* name and/or an outer class name.
429436
*/
430-
private static class ReflectionClassResolver implements ClassResolver {
437+
private static final class ReflectionClassResolver implements ClassResolver {
438+
439+
private static final Predicate<String> PACKAGE_PREDICATE = (name) -> !name.startsWith("java.");
431440

432441
private final Function<GraphQLObjectType, String> classNameFunction;
433442

434-
private final MultiValueMap<String, String> classPrefixes = new LinkedMultiValueMap<>();
443+
private final MultiValueMap<String, String> classPrefixes;
435444

436-
ReflectionClassResolver(Function<GraphQLObjectType, String> classNameFunction) {
437-
this.classNameFunction = classNameFunction;
438-
}
445+
private ReflectionClassResolver(
446+
Function<GraphQLObjectType, String> nameFunction, MultiValueMap<String, String> prefixes) {
439447

440-
void addClassPrefix(String interfaceOrUnionTypeName, String classPrefix) {
441-
this.classPrefixes.add(interfaceOrUnionTypeName, classPrefix);
448+
this.classNameFunction = nameFunction;
449+
this.classPrefixes = prefixes;
442450
}
443451

444452
@Override
@@ -455,49 +463,16 @@ public List<Class<?>> resolveClass(GraphQLObjectType objectType, GraphQLNamedOut
455463
}
456464
return Collections.emptyList();
457465
}
458-
}
459-
460-
461-
/**
462-
* Provides methods to look up GraphQL Object and Java type pairs associated
463-
* with GraphQL interface and union types.
464-
*/
465-
private static class InterfaceUnionLookup {
466-
467-
private static final Predicate<String> PACKAGE_PREDICATE = (name) -> !name.startsWith("java.");
468-
469-
private static final LinkedMultiValueMap<GraphQLType, ResolvableType> EMPTY_MULTI_VALUE_MAP = new LinkedMultiValueMap<>(0);
470-
471-
/** Interface or union type name to implementing or member GraphQL-Java types pairs. */
472-
private final Map<String, MultiValueMap<GraphQLType, ResolvableType>> mappings = new LinkedHashMap<>();
473-
474-
InterfaceUnionLookup(
475-
GraphQLSchema schema, Map<String, Map<String, DataFetcher>> dataFetchers,
476-
List<ClassResolver> classResolvers, Function<GraphQLObjectType, String> classNameFunction) {
477-
478-
addReflectionClassResolver(schema, dataFetchers, classNameFunction, classResolvers);
479-
480-
for (GraphQLNamedType type : schema.getAllTypesAsList()) {
481-
if (type instanceof GraphQLUnionType union) {
482-
for (GraphQLNamedOutputType member : union.getTypes()) {
483-
addTypeMapping(union, (GraphQLObjectType) member, classResolvers);
484-
}
485-
}
486-
else if (type instanceof GraphQLObjectType objectType) {
487-
for (GraphQLNamedOutputType interfaceType : objectType.getInterfaces()) {
488-
addTypeMapping(interfaceType, objectType, classResolvers);
489-
}
490-
}
491-
}
492-
}
493466

494-
private static void addReflectionClassResolver(
467+
/**
468+
* Create a resolver that is aware of packages associated with controller
469+
* methods mapped to unions and interfaces.
470+
*/
471+
public static ReflectionClassResolver create(
495472
GraphQLSchema schema, Map<String, Map<String, DataFetcher>> dataFetchers,
496-
Function<GraphQLObjectType, String> classNameFunction, List<ClassResolver> classResolvers) {
497-
498-
ReflectionClassResolver resolver = new ReflectionClassResolver(classNameFunction);
499-
classResolvers.add(resolver);
473+
Function<GraphQLObjectType, String> classNameFunction) {
500474

475+
MultiValueMap<String, String> classPrefixes = new LinkedMultiValueMap<>();
501476
for (Map.Entry<String, Map<String, DataFetcher>> typeEntry : dataFetchers.entrySet()) {
502477
String typeName = typeEntry.getKey();
503478
GraphQLType parentType = schema.getType(typeName);
@@ -517,45 +492,36 @@ private static void addReflectionClassResolver(
517492
Class<?> clazz = pair.resolvableType().resolve(Object.class);
518493
if (PACKAGE_PREDICATE.test(clazz.getPackageName())) {
519494
int index = clazz.getName().indexOf(clazz.getSimpleName());
520-
resolver.addClassPrefix(outputTypeName, clazz.getName().substring(0, index));
495+
classPrefixes.add(outputTypeName, clazz.getName().substring(0, index));
521496
}
522497
else if (fieldEntry.getValue() instanceof SelfDescribingDataFetcher<?> sddf) {
523498
if (sddf.getReturnType().getSource() instanceof MethodParameter param) {
524499
clazz = param.getDeclaringClass();
525500
int index = clazz.getName().indexOf(clazz.getSimpleName());
526-
resolver.addClassPrefix(outputTypeName, clazz.getName().substring(0, index));
501+
classPrefixes.add(outputTypeName, clazz.getName().substring(0, index));
527502
}
528503
}
529504
}
530505
}
531506
}
507+
return new ReflectionClassResolver(classNameFunction, classPrefixes);
532508
}
509+
}
533510

534-
private void addTypeMapping(
535-
GraphQLNamedOutputType interfaceOrUnionType, GraphQLObjectType objectType,
536-
List<ClassResolver> classResolvers) {
537511

538-
List<ResolvableType> resolvableTypes = new ArrayList<>();
512+
/**
513+
* Lookup for GraphQL Object and Java type pairs that are associated with
514+
* GraphQL union and interface types.
515+
*/
516+
private static final class InterfaceUnionLookup {
539517

540-
for (ClassResolver resolver : classResolvers) {
541-
List<Class<?>> classes = resolver.resolveClass(objectType, interfaceOrUnionType);
542-
if (!classes.isEmpty()) {
543-
for (Class<?> clazz : classes) {
544-
ResolvableType resolvableType = ResolvableType.forClass(clazz);
545-
resolvableTypes.add(resolvableType);
546-
}
547-
break;
548-
}
549-
}
518+
private static final LinkedMultiValueMap<GraphQLType, ResolvableType> EMPTY_MAP = new LinkedMultiValueMap<>(0);
550519

551-
if (resolvableTypes.isEmpty()) {
552-
resolvableTypes.add(ResolvableType.NONE);
553-
}
520+
/** Interface or union type name to implementing or member GraphQL-Java types pairs. */
521+
private final Map<String, MultiValueMap<GraphQLType, ResolvableType>> mappings;
554522

555-
for (ResolvableType resolvableType : resolvableTypes) {
556-
String name = interfaceOrUnionType.getName();
557-
this.mappings.computeIfAbsent(name, (n) -> new LinkedMultiValueMap<>()).add(objectType, resolvableType);
558-
}
523+
private InterfaceUnionLookup(Map<String, MultiValueMap<GraphQLType, ResolvableType>> mappings) {
524+
this.mappings = mappings;
559525
}
560526

561527
/**
@@ -565,7 +531,7 @@ private void addTypeMapping(
565531
* pair with {@link ResolvableType#NONE}.
566532
*/
567533
MultiValueMap<GraphQLType, ResolvableType> resolveInterface(GraphQLInterfaceType interfaceType) {
568-
return this.mappings.getOrDefault(interfaceType.getName(), EMPTY_MULTI_VALUE_MAP);
534+
return this.mappings.getOrDefault(interfaceType.getName(), EMPTY_MAP);
569535
}
570536

571537
/**
@@ -575,9 +541,61 @@ MultiValueMap<GraphQLType, ResolvableType> resolveInterface(GraphQLInterfaceType
575541
* pair with {@link ResolvableType#NONE}.
576542
*/
577543
MultiValueMap<GraphQLType, ResolvableType> resolveUnion(GraphQLUnionType unionType) {
578-
return this.mappings.getOrDefault(unionType.getName(), EMPTY_MULTI_VALUE_MAP);
544+
return this.mappings.getOrDefault(unionType.getName(), EMPTY_MAP);
545+
}
546+
547+
/**
548+
* Resolve the class for every union member and interface implementation type,
549+
* and create a lookup instance.
550+
*/
551+
public static InterfaceUnionLookup create(
552+
GraphQLSchema schema, List<ClassResolver> classResolvers) {
553+
554+
Map<String, MultiValueMap<GraphQLType, ResolvableType>> mappings = new LinkedHashMap<>();
555+
556+
for (GraphQLNamedType type : schema.getAllTypesAsList()) {
557+
if (type instanceof GraphQLUnionType union) {
558+
for (GraphQLNamedOutputType member : union.getTypes()) {
559+
addTypeMapping(union, (GraphQLObjectType) member, classResolvers, mappings);
560+
}
561+
}
562+
else if (type instanceof GraphQLObjectType objectType) {
563+
for (GraphQLNamedOutputType interfaceType : objectType.getInterfaces()) {
564+
addTypeMapping(interfaceType, objectType, classResolvers, mappings);
565+
}
566+
}
567+
}
568+
569+
return new InterfaceUnionLookup(mappings);
579570
}
580571

572+
private static void addTypeMapping(
573+
GraphQLNamedOutputType interfaceOrUnionType, GraphQLObjectType objectType,
574+
List<ClassResolver> classResolvers,
575+
Map<String, MultiValueMap<GraphQLType, ResolvableType>> mappings) {
576+
577+
List<ResolvableType> resolvableTypes = new ArrayList<>();
578+
579+
for (ClassResolver resolver : classResolvers) {
580+
List<Class<?>> classes = resolver.resolveClass(objectType, interfaceOrUnionType);
581+
if (!classes.isEmpty()) {
582+
for (Class<?> clazz : classes) {
583+
ResolvableType resolvableType = ResolvableType.forClass(clazz);
584+
resolvableTypes.add(resolvableType);
585+
}
586+
break;
587+
}
588+
}
589+
590+
if (resolvableTypes.isEmpty()) {
591+
resolvableTypes.add(ResolvableType.NONE);
592+
}
593+
594+
for (ResolvableType resolvableType : resolvableTypes) {
595+
String name = interfaceOrUnionType.getName();
596+
mappings.computeIfAbsent(name, (n) -> new LinkedMultiValueMap<>()).add(objectType, resolvableType);
597+
}
598+
}
581599
}
582600

583601

0 commit comments

Comments
 (0)