From a323d22f694b63a18a2b04414b27f5aeabff857a Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Mon, 6 May 2024 21:07:48 +0100 Subject: [PATCH] Fix GraphQL Java 21 compatibility issue Closes gh-963 --- .../DefaultExecutionGraphQlService.java | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/spring-graphql/src/main/java/org/springframework/graphql/execution/DefaultExecutionGraphQlService.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/DefaultExecutionGraphQlService.java index 68da48b8..1bc291b3 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/execution/DefaultExecutionGraphQlService.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/execution/DefaultExecutionGraphQlService.java @@ -16,6 +16,7 @@ package org.springframework.graphql.execution; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import java.util.function.BiFunction; @@ -33,6 +34,8 @@ import org.springframework.graphql.ExecutionGraphQlRequest; import org.springframework.graphql.ExecutionGraphQlResponse; import org.springframework.graphql.ExecutionGraphQlService; import org.springframework.graphql.support.DefaultExecutionGraphQlResponse; +import org.springframework.util.ClassUtils; +import org.springframework.util.ReflectionUtils; /** * {@link ExecutionGraphQlService} that uses a {@link GraphQlSource} to obtain a @@ -43,6 +46,9 @@ import org.springframework.graphql.support.DefaultExecutionGraphQlResponse; */ public class DefaultExecutionGraphQlService implements ExecutionGraphQlService { + private static final boolean belowGraphQlJava22 = ClassUtils.isPresent( + DataLoaderRegistry21Initializer.CLASS_NAME, ExecutionGraphQlService.class.getClassLoader()); + private static final BiFunction RESET_EXECUTION_ID_CONFIGURER = (executionInput, builder) -> builder.executionId(null).build(); @@ -55,11 +61,15 @@ public class DefaultExecutionGraphQlService implements ExecutionGraphQlService { private final boolean isDefaultExecutionIdProvider; + private final Object emptyDataLoaderRegistryInstance; + public DefaultExecutionGraphQlService(GraphQlSource graphQlSource) { this.graphQlSource = graphQlSource; this.isDefaultExecutionIdProvider = (graphQlSource.graphQl().getIdProvider() == ExecutionIdProvider.DEFAULT_EXECUTION_ID_PROVIDER); + this.emptyDataLoaderRegistryInstance = (belowGraphQlJava22) ? + DataLoaderRegistry21Initializer.getInstance() : DataLoaderRegistry22Initializer.getInstance(); } @@ -105,7 +115,7 @@ public class DefaultExecutionGraphQlService implements ExecutionGraphQlService { private ExecutionInput registerDataLoaders(ExecutionInput executionInput) { GraphQLContext graphQLContext = executionInput.getGraphQLContext(); DataLoaderRegistry existingRegistry = executionInput.getDataLoaderRegistry(); - if (existingRegistry == EmptyDataLoaderRegistryInstance.EMPTY_DATALOADER_REGISTRY) { + if (existingRegistry == this.emptyDataLoaderRegistryInstance) { DataLoaderRegistry newRegistry = DataLoaderRegistry.newRegistry().build(); applyDataLoaderRegistrars(newRegistry, graphQLContext); executionInput = executionInput.transform((builder) -> builder.dataLoaderRegistry(newRegistry)); @@ -120,4 +130,30 @@ public class DefaultExecutionGraphQlService implements ExecutionGraphQlService { this.dataLoaderRegistrars.forEach((registrar) -> registrar.registerDataLoaders(registry, graphQLContext)); } + + private static final class DataLoaderRegistry22Initializer { + + public static Object getInstance() { + return EmptyDataLoaderRegistryInstance.EMPTY_DATALOADER_REGISTRY; + } + } + + + private static final class DataLoaderRegistry21Initializer { + + public static final String CLASS_NAME = + "graphql.execution.instrumentation.dataloader.DataLoaderDispatcherInstrumentationState"; + + @SuppressWarnings("DataFlowIssue") + public static Object getInstance() { + try { + Field field = ReflectionUtils.findField(Class.forName(CLASS_NAME), "EMPTY_DATALOADER_REGISTRY"); + return ReflectionUtils.getField(field, null); + } + catch (ClassNotFoundException ex) { + throw new RuntimeException(ex); + } + } + } + }