Unable to inject executionStrategies bean
TL;DR
public class GraphQLWebAutoConfiguration {
@Autowired(required = false)
private Map<String, ExecutionStrategy> executionStrategies;
is populated by spring as map beanName -> bean, when I have some ExecutionStrategy in spring context.
Problem
I was trying to inject my custom executionStrategies bean for ExecutionStrategyProvider creation inside GraphQLWebAutoConfiguration.
In my own @Configuration annotated class I have created simple bean
@Configuration
public class GraphqlConfiguration {
@Bean
public Map<String, ExecutionStrategy> executionStrategies(AsyncTransactionalExecutionStrategy strategy) {
Map<String, ExecutionStrategy> executionStrategyMap = new HashMap<>();
executionStrategyMap.put(QUERY_EXECUTION_STRATEGY, strategy);
executionStrategyMap.put(MUTATION_EXECUTION_STRATEGY, new AsyncExecutionStrategy());
return executionStrategyMap;
}
}
Where AsyncTransactionalExecutionStrategy is another bean (with transaction over whole graphql execution to enable lazy hibernate calls)
@Component
public class AsyncTransactionalExecutionStrategy extends AsyncExecutionStrategy {
@Override
@Transactional
public CompletableFuture<ExecutionResult> execute(ExecutionContext executionContext, ExecutionStrategyParameters parameters) throws NonNullableFieldWasNullException {
return super.execute(executionContext, parameters);
}
}
The problem is, that the executionStrategyProvider(...) inside GraphQLWebAutoConfiguration is called before my configuration and my map bean creation.
public class GraphQLWebAutoConfiguration {
@Autowired(required = false)
private Map<String, ExecutionStrategy> executionStrategies;
executionStrategies is injected with map beanName -> bean (of 1 instance) instead of map from my bean that uses GraphQLWebAutoConfiguration.QUERY_EXECUTION_STRATEGY and alike as keys. The executionStrategyProvider then works unexpectedly - it uses the one strategy for query, mutation and subscription.
Solution (kind of)
The solution is to name my bean using the expected keys
@Component(QUERY_EXECUTION_STRATEGY)
public class AsyncTransactionalExecutionStrategy extends AsyncExecutionStrategy {
and do not use the executionStrategies(...) bean inside my config. This populates the executionStrategies map with proper keys (beanName = expected key). But is this the "right" way that is intended?
I'd say your current solution is more a workaround and a better mechanism should be provided.
For me it worked to define an ExecutionStrategyProvider instead of defining the Map.
@Bean
public ExecutionStrategyProvider executionStrategyProvider(
AsyncTransactionalExecutionStrategy queryExecutionStrategy) {
return new DefaultExecutionStrategyProvider(queryExecutionStrategy, null, null);
}