From 05642488bc8809073dfba239b5189106998f5473 Mon Sep 17 00:00:00 2001 From: "soumik.dutta" Date: Fri, 21 Jun 2024 18:32:17 +0530 Subject: [PATCH 1/2] Add LightOperationExecutor support for parameterless operations. LightDataFetcher do not require materialised DataFetchingEnvironment to execute and are cheaper to run. --- .../execution/LightOperationExecutor.java | 146 ++++++++++++++++++ .../graphql/execution/OperationExecutor.java | 10 +- .../execution/ResolutionEnvironment.java | 66 +++++--- .../graphql/generator/OperationMapper.java | 7 +- .../common/DirectiveValueDeserializer.java | 22 ++- .../mapping/common/EnvironmentInjector.java | 4 +- .../generator/mapping/common/IdAdapter.java | 11 +- .../mapping/core/PublisherAdapter.java | 2 +- .../io/leangen/graphql/InterceptorTest.java | 6 +- 9 files changed, 225 insertions(+), 49 deletions(-) create mode 100644 src/main/java/io/leangen/graphql/execution/LightOperationExecutor.java diff --git a/src/main/java/io/leangen/graphql/execution/LightOperationExecutor.java b/src/main/java/io/leangen/graphql/execution/LightOperationExecutor.java new file mode 100644 index 00000000..321cda11 --- /dev/null +++ b/src/main/java/io/leangen/graphql/execution/LightOperationExecutor.java @@ -0,0 +1,146 @@ +package io.leangen.graphql.execution; + +import graphql.GraphQLException; +import graphql.schema.DataFetchingEnvironment; +import graphql.schema.GraphQLFieldDefinition; +import graphql.schema.LightDataFetcher; +import io.leangen.graphql.generator.mapping.ArgumentInjector; +import io.leangen.graphql.generator.mapping.ConverterRegistry; +import io.leangen.graphql.generator.mapping.DelegatingOutputConverter; +import io.leangen.graphql.metadata.Operation; +import io.leangen.graphql.metadata.Resolver; +import io.leangen.graphql.metadata.strategy.value.ValueMapper; +import io.leangen.graphql.util.Utils; +import jdk.jshell.spi.ExecutionControl; +import org.dataloader.BatchLoaderEnvironment; + +import java.util.*; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +/** + * Created by soumik.dutta on 9/21/24. + *

+ * LightOperationExecutor is a performance improvement over OperationExecutor for simple queries as it implements LightDataFetcher interface from GraphQL-Java #2953 + *
+ * LightDataFetcher implementations do not require DataFetchingEnvironment for getting values and are considered cheaper to execute as DFE is not constructed for the query + */ +public class LightOperationExecutor extends OperationExecutor implements LightDataFetcher { + + private final Operation operation; + private final ValueMapper valueMapper; + private final GlobalEnvironment globalEnvironment; + private final ConverterRegistry converterRegistry; + private final DerivedTypeRegistry derivedTypes; + private final Map> innerInterceptors; + private final Map> outerInterceptors; + private final Map NO_ARGUMENTS = new HashMap<>(); + + + public LightOperationExecutor(Operation operation, ValueMapper valueMapper, GlobalEnvironment globalEnvironment, ResolverInterceptorFactory interceptorFactory) { + super(operation, valueMapper, globalEnvironment, interceptorFactory); + this.operation = operation; + this.valueMapper = valueMapper; + this.globalEnvironment = globalEnvironment; + this.converterRegistry = optimizeConverters(operation.getResolvers(), globalEnvironment.converters); + this.derivedTypes = deriveTypes(operation.getResolvers(), converterRegistry); + this.innerInterceptors = operation.getResolvers() + .stream() + .collect(Collectors.toMap(Function.identity(), + res -> interceptorFactory.getInterceptors(new ResolverInterceptorFactoryParams(res)))); + this.outerInterceptors = operation.getResolvers() + .stream() + .collect(Collectors.toMap(Function.identity(), + res -> interceptorFactory.getOuterInterceptors(new ResolverInterceptorFactoryParams(res)))); + } + + @SuppressWarnings("unchecked") + private static void sneakyThrow(Throwable t) throws T { + throw (T) t; + } + + @Override + public Object get(GraphQLFieldDefinition fieldDefinition, Object sourceObject, Supplier env) throws Exception { + // TODO: fix setting clientMutationId as this requires materialized DataFetchingEnvironment, something we are avoiding in LightOperationExecutor + // ContextUtils.setClientMutationId(env.getContext(), env.getArgument(CLIENT_MUTATION_ID)); + + Resolver resolver = this.operation.getApplicableResolver(NO_ARGUMENTS.keySet()); + if (resolver == null) { + throw new GraphQLException( + "Resolver for operation " + operation.getName() + " accepting arguments: " + NO_ARGUMENTS.keySet() + " not implemented"); + } + ResolutionEnvironment resolutionEnvironment = new ResolutionEnvironment(resolver, env, this.valueMapper, this.globalEnvironment, + this.converterRegistry, this.derivedTypes); + return execute(resolver, resolutionEnvironment, sourceObject); + } + + @Override + public Object get(DataFetchingEnvironment env) throws Exception { + throw new ExecutionControl.NotImplementedException( + "LightOperationExecutor does not require materialised DataFetchingEnvironment and so does not implement it. Use OperationExecutor instead."); + } + + public Object execute(List keys, Map arguments, BatchLoaderEnvironment env) throws Exception { + Resolver resolver = this.operation.getApplicableResolver(arguments.keySet()); + if (resolver == null) { + throw new GraphQLException("Batch loader for operation " + operation.getName() + " not implemented"); + } + ResolutionEnvironment resolutionEnvironment = new ResolutionEnvironment(resolver, keys, env, this.valueMapper, this.globalEnvironment, + this.converterRegistry, this.derivedTypes); + return execute(resolver, resolutionEnvironment, arguments); + } + + /** + * Prepares input arguments by calling respective {@link ArgumentInjector}s + * and invokes the underlying resolver method/field + * + * @param resolver The resolver to be invoked once the arguments are prepared + * @param resolutionEnvironment An object containing all contextual information needed during operation resolution + * @param sourceObject Object of which the method is being called + * @return The result returned by the underlying method/field, potentially proxied and wrapped + * @throws Exception If the invocation of the underlying method/field or any of the interceptors throws + */ + private Object execute(Resolver resolver, ResolutionEnvironment resolutionEnvironment, Object sourceObject) throws Exception { + final Object[] NO_ARGUMENTS = new Object[]{}; + InvocationContext invocationContext = new InvocationContext(operation, resolver, resolutionEnvironment, NO_ARGUMENTS); + Queue interceptors = new ArrayDeque<>(this.outerInterceptors.get(resolver)); + interceptors.add( + (ctx, cont) -> resolutionEnvironment.convertOutput(cont.proceed(ctx), resolver.getTypedElement(), resolver.getReturnType())); + interceptors.addAll(this.innerInterceptors.get(resolver)); + interceptors.add((ctx, cont) -> { + try { + return resolver.resolve(sourceObject, NO_ARGUMENTS); + } catch (ReflectiveOperationException e) { + sneakyThrow(unwrap(e)); + } + return null; //never happens, needed because of sneakyThrow + }); + return execute(invocationContext, interceptors); + } + + private Object execute(InvocationContext context, Queue interceptors) throws Exception { + return interceptors.remove().aroundInvoke(context, (ctx) -> execute(ctx, interceptors)); + } + + private ConverterRegistry optimizeConverters(Collection resolvers, ConverterRegistry converters) { + return converters.optimize(resolvers.stream().map(Resolver::getTypedElement).collect(Collectors.toList())); + } + + private DerivedTypeRegistry deriveTypes(Collection resolvers, ConverterRegistry converterRegistry) { + return new DerivedTypeRegistry(resolvers.stream().map(Resolver::getTypedElement).collect(Collectors.toList()), + Utils.extractInstances(converterRegistry.getOutputConverters(), DelegatingOutputConverter.class).collect(Collectors.toList())); + } + + private Throwable unwrap(ReflectiveOperationException e) { + Throwable cause = e.getCause(); + if (cause != null && cause != e) { + return cause; + } + return e; + } + + public Operation getOperation() { + return operation; + } +} \ No newline at end of file diff --git a/src/main/java/io/leangen/graphql/execution/OperationExecutor.java b/src/main/java/io/leangen/graphql/execution/OperationExecutor.java index 2ebca436..3b916cbd 100644 --- a/src/main/java/io/leangen/graphql/execution/OperationExecutor.java +++ b/src/main/java/io/leangen/graphql/execution/OperationExecutor.java @@ -4,6 +4,7 @@ import graphql.execution.DataFetcherResult; import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; +import graphql.schema.GraphQLFieldDefinition; import io.leangen.graphql.generator.mapping.ArgumentInjector; import io.leangen.graphql.generator.mapping.ConverterRegistry; import io.leangen.graphql.generator.mapping.DelegatingOutputConverter; @@ -13,10 +14,12 @@ import io.leangen.graphql.metadata.strategy.value.ValueMapper; import io.leangen.graphql.util.ContextUtils; import io.leangen.graphql.util.Utils; +import jdk.jshell.spi.ExecutionControl; import org.dataloader.BatchLoaderEnvironment; import java.util.*; import java.util.function.Function; +import java.util.function.Supplier; import java.util.stream.Collectors; import static io.leangen.graphql.util.GraphQLUtils.CLIENT_MUTATION_ID; @@ -46,6 +49,11 @@ public OperationExecutor(Operation operation, ValueMapper valueMapper, GlobalEnv res -> interceptorFactory.getOuterInterceptors(new ResolverInterceptorFactoryParams(res)))); } + public Object get(GraphQLFieldDefinition fieldDefinition, Object sourceObject, Supplier env) throws Exception { + throw new ExecutionControl.NotImplementedException( + "OperationExecutor does not implement fetching DataFetchingEnvironment using a Supplier. Use LightOperationExecutor instead."); + } + @Override public Object get(DataFetchingEnvironment env) throws Exception { ContextUtils.setClientMutationId(env.getContext(), env.getArgument(CLIENT_MUTATION_ID)); @@ -142,4 +150,4 @@ private static void sneakyThrow(Throwable t) throws T { public Operation getOperation() { return operation; } -} +} \ No newline at end of file diff --git a/src/main/java/io/leangen/graphql/execution/ResolutionEnvironment.java b/src/main/java/io/leangen/graphql/execution/ResolutionEnvironment.java index 31646a28..e61355b4 100644 --- a/src/main/java/io/leangen/graphql/execution/ResolutionEnvironment.java +++ b/src/main/java/io/leangen/graphql/execution/ResolutionEnvironment.java @@ -5,9 +5,6 @@ import graphql.GraphqlErrorBuilder; import graphql.execution.ExecutionStepInfo; import graphql.schema.DataFetchingEnvironment; -import graphql.schema.GraphQLNamedType; -import graphql.schema.GraphQLOutputType; -import graphql.schema.GraphQLSchema; import io.leangen.graphql.generator.mapping.ArgumentInjectorParams; import io.leangen.graphql.generator.mapping.ConverterRegistry; import io.leangen.graphql.generator.mapping.DelegatingOutputConverter; @@ -25,6 +22,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Supplier; /** * @author Bojan Tomic (kaqqao) @@ -38,10 +36,11 @@ public class ResolutionEnvironment { public final Resolver resolver; public final ValueMapper valueMapper; public final GlobalEnvironment globalEnvironment; - public final GraphQLOutputType fieldType; - public final GraphQLNamedType parentType; - public final GraphQLSchema graphQLSchema; - public final DataFetchingEnvironment dataFetchingEnvironment; + + private final DataFetchingEnvironment dataFetchingEnvironment; + private final Supplier dataFetchingEnvironmentSupplier; + private final boolean isDataFetchingEnvironmentSupplied; + public final BatchLoaderEnvironment batchLoaderEnvironment; public final Map arguments; public final List errors; @@ -58,10 +57,11 @@ public ResolutionEnvironment(Resolver resolver, DataFetchingEnvironment env, Val this.resolver = resolver; this.valueMapper = valueMapper; this.globalEnvironment = globalEnvironment; - this.fieldType = env.getFieldType(); - this.parentType = (GraphQLNamedType) env.getParentType(); - this.graphQLSchema = env.getGraphQLSchema(); + this.dataFetchingEnvironment = env; + this.dataFetchingEnvironmentSupplier = null; + this.isDataFetchingEnvironmentSupplied = false; + this.batchLoaderEnvironment = null; this.arguments = new HashMap<>(); this.errors = new ArrayList<>(); @@ -79,10 +79,11 @@ public ResolutionEnvironment(Resolver resolver, List keys, BatchLoaderEn this.resolver = resolver; this.valueMapper = valueMapper; this.globalEnvironment = globalEnvironment; - this.fieldType = inner != null ? inner.getFieldType() : null; - this.parentType = inner != null ? (GraphQLNamedType) inner.getParentType() : null; - this.graphQLSchema = inner != null ? inner.getGraphQLSchema() : null; + this.dataFetchingEnvironment = null; + this.dataFetchingEnvironmentSupplier = null; + this.isDataFetchingEnvironmentSupplied = false; + this.batchLoaderEnvironment = env; this.arguments = new HashMap<>(); this.errors = new ArrayList<>(); @@ -90,6 +91,31 @@ public ResolutionEnvironment(Resolver resolver, List keys, BatchLoaderEn this.derivedTypes = derivedTypes; } + public ResolutionEnvironment(Resolver resolver, Supplier env, ValueMapper valueMapper, GlobalEnvironment globalEnvironment, + ConverterRegistry converters, DerivedTypeRegistry derivedTypes) { + + this.context = null; + this.rootContext = null; + this.batchContext = null; + this.resolver = resolver; + this.valueMapper = valueMapper; + this.globalEnvironment = globalEnvironment; + + this.dataFetchingEnvironment = null; + this.dataFetchingEnvironmentSupplier = env; + this.isDataFetchingEnvironmentSupplied = true; + + this.batchLoaderEnvironment = null; + this.arguments = new HashMap<>(); + this.errors = new ArrayList<>(); + this.converters = converters; + this.derivedTypes = derivedTypes; + } + + public final DataFetchingEnvironment getDataFetchingEnvironment() { + return isDataFetchingEnvironmentSupplied ? dataFetchingEnvironmentSupplier.get() : dataFetchingEnvironment; + } + public S convertOutput(T output, AnnotatedElement element, AnnotatedType type) { if (output == null) { return null; @@ -120,7 +146,7 @@ public List getDerived(AnnotatedType type) { } public Object getInputValue(Object input, OperationArgument argument) { - boolean argValuePresent = dataFetchingEnvironment != null && dataFetchingEnvironment.containsArgument(argument.getName()); + boolean argValuePresent = getDataFetchingEnvironment() != null && getDataFetchingEnvironment().containsArgument(argument.getName()); ArgumentInjectorParams params = new ArgumentInjectorParams(input, argValuePresent, argument, this); Object value = this.globalEnvironment.injectors.getInjector(argument.getJavaType(), argument.getParameter()).getArgumentValue(params); if (argValuePresent) { @@ -134,8 +160,8 @@ public void addError(String message, Object... formatArgs) { } public GraphQLError createError(String message, Object... formatArgs) { - GraphqlErrorBuilder builder = dataFetchingEnvironment != null - ? GraphqlErrorBuilder.newError(dataFetchingEnvironment) + GraphqlErrorBuilder builder = getDataFetchingEnvironment() != null + ? GraphqlErrorBuilder.newError(getDataFetchingEnvironment()) : GraphqlErrorBuilder.newError(); return builder .message(message, formatArgs) @@ -144,7 +170,7 @@ public GraphQLError createError(String message, Object... formatArgs) { } public Directives getDirectives(ExecutionStepInfo step) { - return new Directives(dataFetchingEnvironment, step); + return new Directives(getDataFetchingEnvironment(), step); } public Directives getDirectives() { @@ -156,8 +182,8 @@ public Object getGlobalContext() { } public boolean isSubscription() { - return dataFetchingEnvironment != null - && dataFetchingEnvironment.getParentType() == dataFetchingEnvironment.getGraphQLSchema().getSubscriptionType(); + return getDataFetchingEnvironment() != null + && getDataFetchingEnvironment().getParentType() == getDataFetchingEnvironment().getGraphQLSchema().getSubscriptionType(); } private static DataFetchingEnvironment dataFetchingEnvironment(List keyContexts) { @@ -166,4 +192,4 @@ private static DataFetchingEnvironment dataFetchingEnvironment(List keyC } return (DataFetchingEnvironment) keyContexts.get(0); } -} +} \ No newline at end of file diff --git a/src/main/java/io/leangen/graphql/generator/OperationMapper.java b/src/main/java/io/leangen/graphql/generator/OperationMapper.java index 8ad4f579..676d8366 100644 --- a/src/main/java/io/leangen/graphql/generator/OperationMapper.java +++ b/src/main/java/io/leangen/graphql/generator/OperationMapper.java @@ -4,6 +4,7 @@ import graphql.schema.*; import io.leangen.geantyref.GenericTypeReflector; import io.leangen.graphql.annotations.GraphQLId; +import io.leangen.graphql.execution.LightOperationExecutor; import io.leangen.graphql.execution.OperationExecutor; import io.leangen.graphql.generator.mapping.TypeMapper; import io.leangen.graphql.generator.mapping.TypeMappingEnvironment; @@ -406,7 +407,11 @@ private DataFetcher createResolver(String parentType, Operation operation, Bu .filter(OperationArgument::isMappable) .map(OperationArgument::getJavaType); ValueMapper valueMapper = buildContext.createValueMapper(inputTypes); - OperationExecutor executor = new OperationExecutor(operation, valueMapper, buildContext.globalEnvironment, buildContext.interceptorFactory); + OperationExecutor executor = operation.getArguments().isEmpty() ? + new LightOperationExecutor(operation, valueMapper, buildContext.globalEnvironment, + buildContext.interceptorFactory) : + new OperationExecutor(operation, valueMapper, buildContext.globalEnvironment, + buildContext.interceptorFactory); if (operation.isBatched()) { String loaderName = parentType + ':' + operation.getName(); BatchLoaderWithContext batchLoader = batchloaderFactory.createBatchLoader(executor); diff --git a/src/main/java/io/leangen/graphql/generator/mapping/common/DirectiveValueDeserializer.java b/src/main/java/io/leangen/graphql/generator/mapping/common/DirectiveValueDeserializer.java index 62a098ba..d98264ab 100644 --- a/src/main/java/io/leangen/graphql/generator/mapping/common/DirectiveValueDeserializer.java +++ b/src/main/java/io/leangen/graphql/generator/mapping/common/DirectiveValueDeserializer.java @@ -11,20 +11,11 @@ import java.lang.reflect.AnnotatedType; import java.lang.reflect.Parameter; -import java.util.Arrays; -import java.util.Collection; -import java.util.Map; -import java.util.Objects; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; -import static graphql.introspection.Introspection.DirectiveLocation.FIELD; -import static graphql.introspection.Introspection.DirectiveLocation.FRAGMENT_DEFINITION; -import static graphql.introspection.Introspection.DirectiveLocation.FRAGMENT_SPREAD; -import static graphql.introspection.Introspection.DirectiveLocation.INLINE_FRAGMENT; -import static graphql.introspection.Introspection.DirectiveLocation.MUTATION; -import static graphql.introspection.Introspection.DirectiveLocation.QUERY; +import static graphql.introspection.Introspection.DirectiveLocation.*; public class DirectiveValueDeserializer implements ArgumentInjector { @@ -33,7 +24,7 @@ public class DirectiveValueDeserializer implements ArgumentInjector { @Override public Object getArgumentValue(ArgumentInjectorParams params) { //Can happen inside BatchLoader - if (params.getResolutionEnvironment().dataFetchingEnvironment == null) { + if (params.getResolutionEnvironment().getDataFetchingEnvironment() == null) { //TODO Can this be supported? Since DataFetchingEnvs are saved as key contexts, it sounds possible. throw new IllegalArgumentException("Directive injection isn't supported in BatchLoaders"); } @@ -44,7 +35,12 @@ public Object getArgumentValue(ArgumentInjectorParams params) { String directiveName = Utils.coalesce(descriptor.name(), fallBackDirectiveName); Stream locations = descriptor.locations().length != 0 ? Arrays.stream(descriptor.locations()) - : sortedLocations(params.getResolutionEnvironment().dataFetchingEnvironment.getGraphQLSchema().getDirective(directiveName).validLocations()); + : + sortedLocations(params.getResolutionEnvironment() + .getDataFetchingEnvironment() + .getGraphQLSchema() + .getDirective(directiveName) + .validLocations()); Directives directives = env.getDirectives(); Stream> rawValues = locations .map(loc -> directives.find(loc, directiveName)) diff --git a/src/main/java/io/leangen/graphql/generator/mapping/common/EnvironmentInjector.java b/src/main/java/io/leangen/graphql/generator/mapping/common/EnvironmentInjector.java index bfe22066..b6b6f766 100644 --- a/src/main/java/io/leangen/graphql/generator/mapping/common/EnvironmentInjector.java +++ b/src/main/java/io/leangen/graphql/generator/mapping/common/EnvironmentInjector.java @@ -27,11 +27,11 @@ public Object getArgumentValue(ArgumentInjectorParams params) { return params.getResolutionEnvironment(); } if (GenericTypeReflector.isSuperType(setOfStrings, params.getType().getType())) { - return params.getResolutionEnvironment().dataFetchingEnvironment.getSelectionSet().getImmediateFields() + return params.getResolutionEnvironment().getDataFetchingEnvironment().getSelectionSet().getImmediateFields() .stream().map(SelectedField::getName).collect(Collectors.toSet()); } if (MergedField.class.equals(raw)) { - return params.getResolutionEnvironment().dataFetchingEnvironment.getMergedField(); + return params.getResolutionEnvironment().getDataFetchingEnvironment().getMergedField(); } if (ValueMapper.class.isAssignableFrom(raw)) { return params.getResolutionEnvironment().valueMapper; diff --git a/src/main/java/io/leangen/graphql/generator/mapping/common/IdAdapter.java b/src/main/java/io/leangen/graphql/generator/mapping/common/IdAdapter.java index bd3d4750..bc57944c 100644 --- a/src/main/java/io/leangen/graphql/generator/mapping/common/IdAdapter.java +++ b/src/main/java/io/leangen/graphql/generator/mapping/common/IdAdapter.java @@ -2,17 +2,13 @@ import graphql.Scalars; import graphql.schema.GraphQLInputType; +import graphql.schema.GraphQLNamedType; import graphql.schema.GraphQLOutputType; import io.leangen.geantyref.GenericTypeReflector; import io.leangen.graphql.annotations.GraphQLId; import io.leangen.graphql.execution.GlobalEnvironment; import io.leangen.graphql.execution.ResolutionEnvironment; -import io.leangen.graphql.generator.mapping.ArgumentInjector; -import io.leangen.graphql.generator.mapping.ArgumentInjectorParams; -import io.leangen.graphql.generator.mapping.InputConverter; -import io.leangen.graphql.generator.mapping.OutputConverter; -import io.leangen.graphql.generator.mapping.TypeMapper; -import io.leangen.graphql.generator.mapping.TypeMappingEnvironment; +import io.leangen.graphql.generator.mapping.*; import io.leangen.graphql.metadata.strategy.value.ValueMapper; import java.lang.reflect.AnnotatedElement; @@ -43,7 +39,8 @@ public GraphQLInputType toGraphQLInputType(AnnotatedType javaType, Set original, AnnotatedType type, Resolutio @SuppressWarnings("WeakerAccess") protected Object convertOutputForNonSubscription(Publisher original, AnnotatedType type, ResolutionEnvironment resolutionEnvironment) { - return collect(original, resolutionEnvironment.dataFetchingEnvironment.getExecutionStepInfo()); + return collect(original, resolutionEnvironment.getDataFetchingEnvironment().getExecutionStepInfo()); } @Override diff --git a/src/test/java/io/leangen/graphql/InterceptorTest.java b/src/test/java/io/leangen/graphql/InterceptorTest.java index 0872cc0c..aaa9a3f2 100644 --- a/src/test/java/io/leangen/graphql/InterceptorTest.java +++ b/src/test/java/io/leangen/graphql/InterceptorTest.java @@ -28,9 +28,7 @@ import java.util.Set; import static io.leangen.graphql.support.LogAssertions.assertWarningsLogged; -import static io.leangen.graphql.support.QueryResultAssertions.assertErrorsEqual; -import static io.leangen.graphql.support.QueryResultAssertions.assertNoErrors; -import static io.leangen.graphql.support.QueryResultAssertions.assertValueAtPathEquals; +import static io.leangen.graphql.support.QueryResultAssertions.*; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -146,7 +144,7 @@ private static class AuthInterceptor implements ResolverInterceptor { @Override public Object aroundInvoke(InvocationContext context, Continuation continuation) throws Exception { Auth auth = context.getResolver().getExecutable().getDelegate().getAnnotation(Auth.class); - User currentUser = context.getResolutionEnvironment().dataFetchingEnvironment.getContext(); + User currentUser = context.getResolutionEnvironment().getDataFetchingEnvironment().getContext(); if (auth != null && !currentUser.getRoles().containsAll(Arrays.asList(auth.rolesRequired()))) { throw new IllegalAccessException("Access denied"); // or return null } From bf95f6c966ca837c0d570acf830d1547cb81b830 Mon Sep 17 00:00:00 2001 From: "soumik.dutta" Date: Fri, 28 Jun 2024 13:20:28 +0530 Subject: [PATCH 2/2] Fix errors in test by allowing illegal calls to LightOperationExecutor.get(DataFetchingEnvironment) to execute --- .../graphql/execution/LightOperationExecutor.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/io/leangen/graphql/execution/LightOperationExecutor.java b/src/main/java/io/leangen/graphql/execution/LightOperationExecutor.java index 321cda11..a64115d8 100644 --- a/src/main/java/io/leangen/graphql/execution/LightOperationExecutor.java +++ b/src/main/java/io/leangen/graphql/execution/LightOperationExecutor.java @@ -11,8 +11,9 @@ import io.leangen.graphql.metadata.Resolver; import io.leangen.graphql.metadata.strategy.value.ValueMapper; import io.leangen.graphql.util.Utils; -import jdk.jshell.spi.ExecutionControl; import org.dataloader.BatchLoaderEnvironment; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.*; import java.util.function.Function; @@ -28,6 +29,7 @@ */ public class LightOperationExecutor extends OperationExecutor implements LightDataFetcher { + private static final Logger log = LoggerFactory.getLogger(LightOperationExecutor.class); private final Operation operation; private final ValueMapper valueMapper; private final GlobalEnvironment globalEnvironment; @@ -77,8 +79,9 @@ public Object get(GraphQLFieldDefinition fieldDefinition, Object sourceObject, S @Override public Object get(DataFetchingEnvironment env) throws Exception { - throw new ExecutionControl.NotImplementedException( - "LightOperationExecutor does not require materialised DataFetchingEnvironment and so does not implement it. Use OperationExecutor instead."); + log.warn( + "LightDataFetcher should not be called with materialised dfe. \nThis should be marked as not implemented. However using DataLoaderDispatcherInstrumentation causes problem with the `instance of LightDataFetcher` check in ExecutionStrategy in GraphQL-Java"); + return super.get(env); } public Object execute(List keys, Map arguments, BatchLoaderEnvironment env) throws Exception {