Extract ContextManager from ReactorDataFetcherAdapter
This change separates the Reactor ContextView propagation into an independent utility class to enable internal re-use. See gh-52
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.graphql.execution;
|
||||
|
||||
import graphql.ExecutionInput;
|
||||
import graphql.GraphQLContext;
|
||||
import graphql.schema.DataFetchingEnvironment;
|
||||
import reactor.util.context.ContextView;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Package private utility class for propagating a Reactor {@link ContextView}
|
||||
* through the {@link ExecutionInput} and the {@link DataFetchingEnvironment}
|
||||
* of a request.
|
||||
*/
|
||||
abstract class ContextManager {
|
||||
|
||||
private static final String REACTOR_CONTEXT_KEY =
|
||||
ReactorDataFetcherAdapter.class.getName() + ".REACTOR_CONTEXT";
|
||||
|
||||
|
||||
/**
|
||||
* Save the given Reactor ContextView in the an {@link ExecutionInput} for
|
||||
* later access through the {@link DataFetchingEnvironment}.
|
||||
*/
|
||||
static void setReactorContext(ContextView contextView, ExecutionInput input) {
|
||||
((GraphQLContext) input.getContext()).put(REACTOR_CONTEXT_KEY, contextView);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Reactor ContextView saved in the given DataFetchingEnvironment,
|
||||
* or null if not present.
|
||||
*/
|
||||
@Nullable
|
||||
static ContextView getReactorContext(DataFetchingEnvironment environment) {
|
||||
GraphQLContext graphQlContext = environment.getContext();
|
||||
return graphQlContext.get(REACTOR_CONTEXT_KEY);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -40,7 +40,7 @@ public class ExecutionGraphQlService implements GraphQlService {
|
||||
public Mono<ExecutionResult> execute(ExecutionInput input) {
|
||||
GraphQL graphQl = this.graphQlSource.graphQl();
|
||||
return Mono.deferContextual(contextView -> {
|
||||
ReactorDataFetcherAdapter.addReactorContext(input, contextView);
|
||||
ContextManager.setReactorContext(contextView, input);
|
||||
return Mono.fromFuture(graphQl.executeAsync(input));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -15,10 +15,7 @@
|
||||
*/
|
||||
package org.springframework.graphql.execution;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import graphql.ExecutionInput;
|
||||
import graphql.GraphQLContext;
|
||||
import graphql.schema.DataFetcher;
|
||||
import graphql.schema.DataFetchingEnvironment;
|
||||
import graphql.schema.GraphQLCodeRegistry;
|
||||
@@ -34,9 +31,7 @@ import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.context.ContextView;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Adapter that can wrap a registered {@link DataFetcher} and enable it to return
|
||||
@@ -46,10 +41,6 @@ import org.springframework.util.ClassUtils;
|
||||
*/
|
||||
class ReactorDataFetcherAdapter implements DataFetcher<Object> {
|
||||
|
||||
private static final String REACTOR_CONTEXT_KEY =
|
||||
ReactorDataFetcherAdapter.class.getName() + ".REACTOR_CONTEXT";
|
||||
|
||||
|
||||
private final DataFetcher<?> delegate;
|
||||
|
||||
private final boolean subscription;
|
||||
@@ -67,7 +58,7 @@ class ReactorDataFetcherAdapter implements DataFetcher<Object> {
|
||||
Object value = this.delegate.get(environment);
|
||||
|
||||
if (this.subscription) {
|
||||
ContextView context = getReactorContext(environment);
|
||||
ContextView context = ContextManager.getReactorContext(environment);
|
||||
return (context != null ? Flux.from((Publisher<?>) value).contextWrite(context) : value);
|
||||
}
|
||||
|
||||
@@ -77,7 +68,7 @@ class ReactorDataFetcherAdapter implements DataFetcher<Object> {
|
||||
|
||||
if (value instanceof Mono) {
|
||||
Mono<?> valueMono = (Mono<?>) value;
|
||||
ContextView reactorContext = getReactorContext(environment);
|
||||
ContextView reactorContext = ContextManager.getReactorContext(environment);
|
||||
if (reactorContext != null) {
|
||||
valueMono = valueMono.contextWrite(reactorContext);
|
||||
}
|
||||
@@ -87,21 +78,6 @@ class ReactorDataFetcherAdapter implements DataFetcher<Object> {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ContextView getReactorContext(DataFetchingEnvironment environment) {
|
||||
GraphQLContext graphQlContext = environment.getContext();
|
||||
return graphQlContext.get(REACTOR_CONTEXT_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the given Reactor Context into the {@link ExecutionInput} context
|
||||
* for later retrieval from the {@link DataFetchingEnvironment}.
|
||||
*/
|
||||
public static void addReactorContext(ExecutionInput executionInput, ContextView reactorContext) {
|
||||
GraphQLContext graphQlContext = (GraphQLContext) executionInput.getContext();
|
||||
graphQlContext.put(REACTOR_CONTEXT_KEY, reactorContext);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@link GraphQLTypeVisitor} that wraps non-GraphQL data fetchers and
|
||||
@@ -121,10 +97,8 @@ class ReactorDataFetcherAdapter implements DataFetcher<Object> {
|
||||
return TraversalControl.CONTINUE;
|
||||
}
|
||||
|
||||
Method method = ClassUtils.getMethod(dataFetcher.getClass(), "get", DataFetchingEnvironment.class);
|
||||
method = ClassUtils.getMostSpecificMethod(method, dataFetcher.getClass());
|
||||
|
||||
dataFetcher = new ReactorDataFetcherAdapter(dataFetcher, parent.getName().equals("Subscription"));
|
||||
boolean handlesSubscription = parent.getName().equals("Subscription");
|
||||
dataFetcher = new ReactorDataFetcherAdapter(dataFetcher, handlesSubscription);
|
||||
codeRegistry.dataFetcher(parent, fieldDefinition, dataFetcher);
|
||||
return TraversalControl.CONTINUE;
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ public class ReactorDataFetcherAdapterTests {
|
||||
|
||||
private ExecutionInput executionInput(String query, Context reactorContext) {
|
||||
ExecutionInput input = ExecutionInput.newExecutionInput().query(query).build();
|
||||
ReactorDataFetcherAdapter.addReactorContext(input, reactorContext);
|
||||
ContextManager.setReactorContext(reactorContext, input);
|
||||
return input;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user