From f35495004caefe9c185dfbb43fdb04bbd028c530 Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Wed, 8 May 2024 21:05:38 +0100 Subject: [PATCH] Improve logging of controller method mappings --- .../federation/FederationSchemaFactory.java | 8 ++++ .../AnnotatedControllerConfigurer.java | 33 +++++++++++++- .../AnnotatedControllerDetectionSupport.java | 43 +++++-------------- 3 files changed, 49 insertions(+), 35 deletions(-) diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/federation/FederationSchemaFactory.java b/spring-graphql/src/main/java/org/springframework/graphql/data/federation/FederationSchemaFactory.java index d6eff3de..f89a672f 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/federation/FederationSchemaFactory.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/federation/FederationSchemaFactory.java @@ -22,6 +22,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CompletionStage; import java.util.function.BiFunction; +import java.util.stream.Collectors; import com.apollographql.federation.graphqljava.Federation; import com.apollographql.federation.graphqljava.SchemaTransformer; @@ -98,6 +99,13 @@ public final class FederationSchemaFactory if (this.typeResolver == null) { this.typeResolver = new ClassNameTypeResolver(); } + + if (logger.isTraceEnabled()) { + String formatted = this.handlerMethods.entrySet().stream() + .map((entry) -> entry.getKey() + " -> " + entry.getValue().getShortLogMessage()) + .collect(Collectors.joining("\n", "\n", "\n")); + logger.trace("@EntityMapping registrations:" + formatted); + } } @Override diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerConfigurer.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerConfigurer.java index 4049136e..804c0a63 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerConfigurer.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerConfigurer.java @@ -257,9 +257,13 @@ public class AnnotatedControllerConfigurer allInfos.forEach((info) -> registerDataFetcher(info, runtimeWiringBuilder)); RuntimeWiring wiring = runtimeWiringBuilder.build(); - subTypeInfos = this.interfaceMappingHelper.filterExistingMappings(subTypeInfos, wiring.getDataFetchers()); + subTypeInfos = this.interfaceMappingHelper.removeExplicitMappings(subTypeInfos, wiring.getDataFetchers()); subTypeInfos.forEach((info) -> registerDataFetcher(info, runtimeWiringBuilder)); + + if (logger.isTraceEnabled()) { + logger.trace("Controller method registrations:" + formatRegistrations(runtimeWiringBuilder)); + } } @Override @@ -403,6 +407,16 @@ public class AnnotatedControllerConfigurer "Mono>, Map, Flux, or Collection: " + handlerMethod); } + @SuppressWarnings("rawtypes") + protected static String formatRegistrations(RuntimeWiring.Builder wiringBuilder) { + return wiringBuilder.build().getDataFetchers().entrySet().stream() + .map((typeEntry) -> typeEntry.getKey() + ":\n" + + typeEntry.getValue().entrySet().stream() + .map((fieldEntry) -> fieldEntry.getKey() + " -> " + fieldEntry.getValue()) + .collect(Collectors.joining("\n\t", "\t", ""))) + .collect(Collectors.joining("\n", "\n", "\n")); + } + /** * Alternative to {@link #configure(RuntimeWiring.Builder)} that registers * data fetchers in a {@link GraphQLCodeRegistry.Builder}. This could be @@ -587,6 +601,11 @@ public class AnnotatedControllerConfigurer Assert.state(dataLoader != null, "No DataLoader for key '" + this.dataLoaderKey + "'"); return dataLoader.load(env.getSource()); } + + @Override + public String toString() { + return getDescription(); + } } @@ -597,6 +616,9 @@ public class AnnotatedControllerConfigurer private final MultiValueMap interfaceMappings = new LinkedMultiValueMap<>(); + /** + * Extract information interface implementation types. + */ void setTypeDefinitionRegistry(TypeDefinitionRegistry registry) { for (TypeDefinition definition : registry.types().values()) { if (definition instanceof ObjectTypeDefinition objectDefinition) { @@ -607,6 +629,10 @@ public class AnnotatedControllerConfigurer } } + /** + * Remove mappings to interface fields, and return mappings for the same + * fields in all implementing types. + */ Set removeInterfaceMappings(Set infos) { Set subTypeMappings = new LinkedHashSet<>(); Iterator it = infos.iterator(); @@ -623,8 +649,11 @@ public class AnnotatedControllerConfigurer return subTypeMappings; } + /** + * Remove mappings that are covered by explicit {@link DataFetcher} registrations. + */ @SuppressWarnings("rawtypes") - Set filterExistingMappings( + Set removeExplicitMappings( Set infos, Map> dataFetchers) { return infos.stream() diff --git a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerDetectionSupport.java b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerDetectionSupport.java index c61028a9..1e059021 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerDetectionSupport.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/data/method/annotation/support/AnnotatedControllerDetectionSupport.java @@ -17,8 +17,6 @@ package org.springframework.graphql.data.method.annotation.support; import java.lang.reflect.Method; -import java.lang.reflect.Type; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashSet; @@ -28,7 +26,6 @@ import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.Executor; import java.util.function.Predicate; -import java.util.stream.Collectors; import graphql.schema.DataFetcher; import org.apache.commons.logging.Log; @@ -258,13 +255,12 @@ public abstract class AnnotatedControllerDetectionSupport implements Applicat continue; } Class beanClass = context.getType(beanName); - findHandlerMethods(beanName, beanClass).forEach((info) -> registerHandlerMethod(info, results)); + findHandlerMethods(beanName, beanClass).forEach((info) -> addHandlerMethod(info, results)); } + return results; } - protected abstract HandlerMethod getHandlerMethod(M mappingInfo); - private Collection findHandlerMethods(Object handler, @Nullable Class handlerClass) { if (handlerClass == null) { return Collections.emptyList(); @@ -274,34 +270,20 @@ public abstract class AnnotatedControllerDetectionSupport implements Applicat Map map = MethodIntrospector.selectMethods( userClass, (Method method) -> getMappingInfo(method, handler, userClass)); - Collection mappingInfos = map.values(); - - if (this.logger.isTraceEnabled() && !mappingInfos.isEmpty()) { - this.logger.trace(formatMappings(userClass, mappingInfos)); - } - - return mappingInfos; + return map.values(); } @Nullable protected abstract M getMappingInfo(Method method, Object handler, Class handlerType); - private String formatMappings(Class handlerType, Collection infos) { - String formattedType = Arrays.stream(ClassUtils.getPackageName(handlerType).split("\\.")) - .map((p) -> p.substring(0, 1)) - .collect(Collectors.joining(".", "", "." + handlerType.getSimpleName())); - return infos.stream() - .map((info) -> { - Method method = getHandlerMethod(info).getMethod(); - String methodParameters = Arrays.stream(method.getGenericParameterTypes()) - .map(Type::getTypeName) - .collect(Collectors.joining(",", "(", ")")); - return info + methodParameters; - }) - .collect(Collectors.joining("\n\t", "\n\t" + formattedType + ":" + "\n\t", "")); + protected HandlerMethod createHandlerMethod(Method originalMethod, Object handler, Class handlerType) { + Method method = AopUtils.selectInvocableMethod(originalMethod, handlerType); + return (handler instanceof String beanName) ? + new HandlerMethod(beanName, obtainApplicationContext().getAutowireCapableBeanFactory(), method) : + new HandlerMethod(handler, method); } - private void registerHandlerMethod(M info, Set results) { + private void addHandlerMethod(M info, Set results) { Assert.state(this.exceptionResolver != null, "afterPropertiesSet not called"); HandlerMethod handlerMethod = getHandlerMethod(info); M existing = results.stream().filter((o) -> o.equals(info)).findFirst().orElse(null); @@ -315,12 +297,7 @@ public abstract class AnnotatedControllerDetectionSupport implements Applicat this.exceptionResolver.registerController(handlerMethod.getBeanType()); } - protected HandlerMethod createHandlerMethod(Method originalMethod, Object handler, Class handlerType) { - Method method = AopUtils.selectInvocableMethod(originalMethod, handlerType); - return (handler instanceof String beanName) ? - new HandlerMethod(beanName, obtainApplicationContext().getAutowireCapableBeanFactory(), method) : - new HandlerMethod(handler, method); - } + protected abstract HandlerMethod getHandlerMethod(M mappingInfo); protected boolean shouldInvokeAsync(HandlerMethod handlerMethod) { return (this.blockingMethodPredicate.test(handlerMethod) && this.executor != null &&