diff --git a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/GraphQlAutoConfiguration.java b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/GraphQlAutoConfiguration.java index 43d5497e..dac49ab5 100644 --- a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/GraphQlAutoConfiguration.java +++ b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/GraphQlAutoConfiguration.java @@ -24,7 +24,6 @@ import java.util.stream.Collectors; import graphql.GraphQL; import graphql.execution.instrumentation.Instrumentation; -import graphql.schema.idl.RuntimeWiring; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -51,50 +50,33 @@ import org.springframework.graphql.execution.GraphQlSource; @EnableConfigurationProperties(GraphQlProperties.class) public class GraphQlAutoConfiguration { + private static final String[] SCHEMA_FILES_EXTENSIONS = new String[] {"*.graphqls", "*.graphql", "*.gql", "*.gqls"}; + @Bean - public GraphQlSource graphQlSource(GraphQlSource.Builder builder) { + public GraphQlSource graphQlSource(ResourcePatternResolver resourcePatternResolver, GraphQlProperties properties, + ObjectProvider exceptionResolversProvider, + ObjectProvider instrumentationsProvider, + ObjectProvider sourceCustomizers, + ObjectProvider wiringCustomizers) throws IOException { + + + List schemaResources = resolveSchemaResources(resourcePatternResolver, properties.getSchema().getLocations()); + GraphQlSource.Builder builder = GraphQlSource.builder().schemaResources(schemaResources.toArray(new Resource[0])) + .exceptionResolvers(exceptionResolversProvider.orderedStream().collect(Collectors.toList())) + .instrumentation(instrumentationsProvider.orderedStream().collect(Collectors.toList())); + wiringCustomizers.orderedStream().forEach((customizer) -> builder.runtimeWiring(customizer::customize)); + sourceCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder)); return builder.build(); } - @Configuration(proxyBeanMethods = false) - @ConditionalOnMissingBean(GraphQlSource.Builder.class) - public static class GraphQlSourceConfiguration { - - private static final String[] SCHEMA_FILES_EXTENSIONS = new String[] {"*.graphqls", "*.graphql", "*.gql", "*.gqls"}; - - @Bean - @ConditionalOnMissingBean - public RuntimeWiring runtimeWiring(ObjectProvider customizers) { - RuntimeWiring.Builder builder = RuntimeWiring.newRuntimeWiring(); - customizers.orderedStream().forEach((customizer) -> customizer.customize(builder)); - return builder.build(); - } - - @Bean - public GraphQlSource.Builder graphQlSourceBuilder(ResourcePatternResolver resourcePatternResolver, GraphQlProperties properties, - RuntimeWiring runtimeWiring, ObjectProvider exceptionResolversProvider, - ObjectProvider instrumentationsProvider, - ObjectProvider customizersProvider) throws IOException { - - List schemaResources = resolveSchemaResources(resourcePatternResolver, properties.getSchema().getLocations()); - GraphQlSource.Builder builder = GraphQlSource.builder().schemaResources(schemaResources.toArray(new Resource[0])) - .runtimeWiring(runtimeWiring) - .exceptionResolvers(exceptionResolversProvider.orderedStream().collect(Collectors.toList())) - .instrumentation(instrumentationsProvider.orderedStream().collect(Collectors.toList())); - customizersProvider.forEach((customizer) -> customizer.customize(builder)); - return builder; - } - - private List resolveSchemaResources(ResourcePatternResolver resolver, List schemaLocations) throws IOException { - List schemaResources = new ArrayList<>(); - for (String location : schemaLocations) { - for (String extension : SCHEMA_FILES_EXTENSIONS) { - schemaResources.addAll(Arrays.asList(resolver.getResources(location + extension))); - } + private List resolveSchemaResources(ResourcePatternResolver resolver, List schemaLocations) throws IOException { + List schemaResources = new ArrayList<>(); + for (String location : schemaLocations) { + for (String extension : SCHEMA_FILES_EXTENSIONS) { + schemaResources.addAll(Arrays.asList(resolver.getResources(location + extension))); } - return schemaResources; } - + return schemaResources; } } diff --git a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/data/GraphQlWebFluxQuerydslAutoConfiguration.java b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/data/GraphQlWebFluxQuerydslAutoConfiguration.java index 63cc14ec..0c6de53b 100644 --- a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/data/GraphQlWebFluxQuerydslAutoConfiguration.java +++ b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/data/GraphQlWebFluxQuerydslAutoConfiguration.java @@ -50,7 +50,7 @@ import org.springframework.graphql.execution.GraphQlSource; @Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) @ConditionalOnClass({GraphQL.class, QuerydslPredicateExecutor.class }) -@ConditionalOnBean(GraphQlSource.Builder.class) +@ConditionalOnBean(GraphQlSource.class) @AutoConfigureAfter(GraphQlAutoConfiguration.class) public class GraphQlWebFluxQuerydslAutoConfiguration { diff --git a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/data/GraphQlWebMvcQuerydslAutoConfiguration.java b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/data/GraphQlWebMvcQuerydslAutoConfiguration.java index 530788ce..92d37cdb 100644 --- a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/data/GraphQlWebMvcQuerydslAutoConfiguration.java +++ b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/data/GraphQlWebMvcQuerydslAutoConfiguration.java @@ -50,7 +50,7 @@ import org.springframework.graphql.execution.GraphQlSource; @Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) @ConditionalOnClass({GraphQL.class, QuerydslPredicateExecutor.class }) -@ConditionalOnBean(GraphQlSource.Builder.class) +@ConditionalOnBean(GraphQlSource.class) @AutoConfigureAfter(GraphQlAutoConfiguration.class) public class GraphQlWebMvcQuerydslAutoConfiguration { diff --git a/spring-graphql/src/main/java/org/springframework/graphql/execution/DefaultGraphQlSourceBuilder.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/DefaultGraphQlSourceBuilder.java index c0970942..4e44720e 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/execution/DefaultGraphQlSourceBuilder.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/execution/DefaultGraphQlSourceBuilder.java @@ -51,7 +51,8 @@ class DefaultGraphQlSourceBuilder implements GraphQlSource.Builder { private final List schemaResources = new ArrayList<>(); - private RuntimeWiring runtimeWiring = RuntimeWiring.newRuntimeWiring().build(); + private Consumer runtimeWiringConfigurers = (builder) -> { + }; private final List exceptionResolvers = new ArrayList<>(); @@ -70,9 +71,9 @@ class DefaultGraphQlSourceBuilder implements GraphQlSource.Builder { } @Override - public GraphQlSource.Builder runtimeWiring(RuntimeWiring runtimeWiring) { - Assert.notNull(runtimeWiring, "RuntimeWiring is required"); - this.runtimeWiring = runtimeWiring; + public GraphQlSource.Builder runtimeWiring(Consumer configurer) { + Assert.notNull(configurer, "RuntimeWiring configurer is required"); + this.runtimeWiringConfigurers = this.runtimeWiringConfigurers.andThen(configurer); return this; } @@ -106,7 +107,9 @@ class DefaultGraphQlSourceBuilder implements GraphQlSource.Builder { .map(this::parseSchemaResource).reduce(TypeDefinitionRegistry::merge) .orElseThrow(() -> new IllegalArgumentException("'schemaResources' should not be empty")); - GraphQLSchema schema = new SchemaGenerator().makeExecutableSchema(registry, this.runtimeWiring); + RuntimeWiring.Builder runtimeWiring = RuntimeWiring.newRuntimeWiring(); + this.runtimeWiringConfigurers.accept(runtimeWiring); + GraphQLSchema schema = new SchemaGenerator().makeExecutableSchema(registry, runtimeWiring.build()); schema = applyTypeVisitors(schema); GraphQL.Builder builder = GraphQL.newGraphQL(schema); diff --git a/spring-graphql/src/main/java/org/springframework/graphql/execution/GraphQlSource.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/GraphQlSource.java index d4625532..b217123c 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/execution/GraphQlSource.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/execution/GraphQlSource.java @@ -79,13 +79,15 @@ public interface GraphQlSource { Builder schemaResources(Resource... resources); /** - * Set a {@link RuntimeWiring} to contribute data fetchers and more. - * @param runtimeWiring the runtime wiring for contribution + * Configure consumers that will be given access to the {@link RuntimeWiring.Builder} used to + * build the {@link RuntimeWiring}. A {@link RuntimeWiring#newRuntimeWiring() default builder} + * instance is created as a starting point. + * @param configurer the runtime wiring configurer * @return the current builder * @see graphql.schema.idl.SchemaGenerator#makeExecutableSchema(TypeDefinitionRegistry, * RuntimeWiring) */ - Builder runtimeWiring(RuntimeWiring runtimeWiring); + Builder runtimeWiring(Consumer configurer); /** * Add {@link DataFetcherExceptionResolver}'s to use for resolving exceptions from diff --git a/spring-graphql/src/test/java/org/springframework/graphql/GraphQlTestUtils.java b/spring-graphql/src/test/java/org/springframework/graphql/GraphQlTestUtils.java index df3cdc54..6a1f5f51 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/GraphQlTestUtils.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/GraphQlTestUtils.java @@ -50,13 +50,9 @@ public abstract class GraphQlTestUtils { public static GraphQlSource.Builder initGraphQlSource(String schemaContent, String typeName, String fieldName, DataFetcher fetcher) { - RuntimeWiring wiring = RuntimeWiring.newRuntimeWiring() - .type(typeName, (builder) -> builder.dataFetcher(fieldName, fetcher)) - .build(); - return GraphQlSource.builder() .schemaResources(new ByteArrayResource(schemaContent.getBytes(StandardCharsets.UTF_8))) - .runtimeWiring(wiring); + .runtimeWiring(wiring -> wiring.type(typeName, (builder) -> builder.dataFetcher(fieldName, fetcher))); } } diff --git a/spring-graphql/src/test/java/org/springframework/graphql/data/QuerydslDataFetcherTests.java b/spring-graphql/src/test/java/org/springframework/graphql/data/QuerydslDataFetcherTests.java index e318dd79..3a03d0e5 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/data/QuerydslDataFetcherTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/data/QuerydslDataFetcherTests.java @@ -282,7 +282,7 @@ class QuerydslDataFetcherTests { if (configurer != null) { TypeRuntimeWiring.Builder typeBuilder = TypeRuntimeWiring.newTypeWiring("Query"); configurer.accept(typeBuilder); - graphQlSourceBuilder.runtimeWiring(RuntimeWiring.newRuntimeWiring().type(typeBuilder).build()); + graphQlSourceBuilder.runtimeWiring(wiring -> wiring.type(typeBuilder)); } GraphQLTypeVisitor visitor = QuerydslDataFetcher.registrationTypeVisitor( diff --git a/spring-graphql/src/test/java/org/springframework/graphql/web/BookTestUtils.java b/spring-graphql/src/test/java/org/springframework/graphql/web/BookTestUtils.java index 470b79fa..c1040f9a 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/web/BookTestUtils.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/web/BookTestUtils.java @@ -70,20 +70,18 @@ public abstract class BookTestUtils { } private static GraphQlSource graphQlSource() { - RuntimeWiring.Builder builder = RuntimeWiring.newRuntimeWiring(); - builder.type(TypeRuntimeWiring.newTypeWiring("Query") - .dataFetcher("bookById", (env) -> { - Long id = Long.parseLong(env.getArgument("id")); - return booksMap.get(id); - })); - builder.type(TypeRuntimeWiring.newTypeWiring("Subscription") - .dataFetcher("bookSearch", (env) -> { - String author = env.getArgument("author"); - return Flux.fromIterable(booksMap.values()).filter((book) -> book.getAuthor().contains(author)); - })); return GraphQlSource.builder() .schemaResources(new ClassPathResource("books/schema.graphqls")) - .runtimeWiring(builder.build()) + .runtimeWiring(builder -> builder.type(TypeRuntimeWiring.newTypeWiring("Query") + .dataFetcher("bookById", (env) -> { + Long id = Long.parseLong(env.getArgument("id")); + return booksMap.get(id); + })) + .type(TypeRuntimeWiring.newTypeWiring("Subscription") + .dataFetcher("bookSearch", (env) -> { + String author = env.getArgument("author"); + return Flux.fromIterable(booksMap.values()).filter((book) -> book.getAuthor().contains(author)); + }))) .build(); }