This commit is contained in:
Stephane Nicoll
2021-06-30 15:10:28 +02:00
committed by Brian Clozel
parent 4a1ee14f88
commit 9d4ebfe743
16 changed files with 90 additions and 99 deletions

View File

@@ -31,7 +31,6 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
@@ -65,18 +64,18 @@ public class GraphQlAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public RuntimeWiring runtimeWiring(ObjectProvider<RuntimeWiringCustomizer> customizers) {
public RuntimeWiring runtimeWiring(ObjectProvider<RuntimeWiringBuilderCustomizer> customizers) {
RuntimeWiring.Builder builder = RuntimeWiring.newRuntimeWiring();
customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
return builder.build();
}
@Bean
public GraphQlSource.Builder graphQlSourceBuilder(ApplicationContext applicationContext, GraphQlProperties properties,
public GraphQlSource.Builder graphQlSourceBuilder(ResourcePatternResolver resourcePatternResolver, GraphQlProperties properties,
RuntimeWiring runtimeWiring, ObjectProvider<DataFetcherExceptionResolver> exceptionResolversProvider,
ObjectProvider<Instrumentation> instrumentationsProvider) throws IOException {
List<Resource> schemaResources = resolveSchemaResources(applicationContext, properties.getSchema().getLocations());
List<Resource> schemaResources = resolveSchemaResources(resourcePatternResolver, properties.getSchema().getLocations());
return GraphQlSource.builder().schemaResources(schemaResources.toArray(new Resource[0]))
.runtimeWiring(runtimeWiring)
.exceptionResolvers(exceptionResolversProvider.orderedStream().collect(Collectors.toList()))

View File

@@ -42,7 +42,7 @@ public class GraphQlProperties {
private final GraphiQL graphiql = new GraphiQL();
private final WebSocket websocket = new WebSocket();
private final Websocket websocket = new Websocket();
public String getPath() {
return this.path;
@@ -60,7 +60,7 @@ public class GraphQlProperties {
return this.graphiql;
}
public WebSocket getWebsocket() {
public Websocket getWebsocket() {
return this.websocket;
}
@@ -152,7 +152,7 @@ public class GraphQlProperties {
}
}
public static class WebSocket {
public static class Websocket {
/**
* Path of the GraphQL WebSocket subscription endpoint.

View File

@@ -65,14 +65,15 @@ import static org.springframework.web.reactive.function.server.RequestPredicates
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@ConditionalOnClass(GraphQL.class)
@ConditionalOnBean(GraphQlSource.class)
@AutoConfigureAfter(GraphQlAutoConfiguration.class)
public class WebFluxGraphQlAutoConfiguration {
@AutoConfigureAfter(GraphQlServiceAutoConfiguration.class)
public class GraphQlWebFluxAutoConfiguration {
private static final Log logger = LogFactory.getLog(WebFluxGraphQlAutoConfiguration.class);
private static final Log logger = LogFactory.getLog(GraphQlWebFluxAutoConfiguration.class);
@Bean
@ConditionalOnBean(GraphQlService.class)
@ConditionalOnMissingBean
public WebGraphQlHandler webGraphQlHandler(ObjectProvider<WebInterceptor> interceptors, GraphQlService service) {
public WebGraphQlHandler webGraphQlHandler(GraphQlService service, ObjectProvider<WebInterceptor> interceptors) {
return WebGraphQlHandler.builder(service)
.interceptors(interceptors.orderedStream().collect(Collectors.toList())).build();
}
@@ -86,7 +87,6 @@ public class WebFluxGraphQlAutoConfiguration {
@Bean
public RouterFunction<ServerResponse> graphQlEndpoint(GraphQlHttpHandler handler, GraphQlSource graphQlSource,
GraphQlProperties properties, ResourceLoader resourceLoader) {
String graphQLPath = properties.getPath();
if (logger.isInfoEnabled()) {
logger.info("GraphQL endpoint HTTP POST " + graphQLPath);
@@ -96,7 +96,7 @@ public class WebFluxGraphQlAutoConfiguration {
.POST(graphQLPath, accept(MediaType.APPLICATION_JSON).and(contentType(MediaType.APPLICATION_JSON)), handler::handleRequest);
if (properties.getGraphiql().isEnabled()) {
Resource resource = resourceLoader.getResource("classpath:graphiql/index.html");
WebFluxGraphiQlHandler graphiQlHandler = new WebFluxGraphiQlHandler(graphQLPath, resource);
GraphiQlWebFluxHandler graphiQlHandler = new GraphiQlWebFluxHandler(graphQLPath, resource);
builder = builder.GET(properties.getGraphiql().getPath(), graphiQlHandler::showGraphiQlPage);
}
if (properties.getSchema().getPrinter().isEnabled()) {
@@ -118,7 +118,6 @@ public class WebFluxGraphQlAutoConfiguration {
@ConditionalOnMissingBean
public GraphQlWebSocketHandler graphQlWebSocketHandler(WebGraphQlHandler webGraphQlHandler,
GraphQlProperties properties, ServerCodecConfigurer configurer) {
return new GraphQlWebSocketHandler(webGraphQlHandler, configurer,
properties.getWebsocket().getConnectionInitTimeout());
}
@@ -126,7 +125,6 @@ public class WebFluxGraphQlAutoConfiguration {
@Bean
public HandlerMapping graphQlWebSocketEndpoint(GraphQlWebSocketHandler graphQlWebSocketHandler,
GraphQlProperties properties) {
String path = properties.getWebsocket().getPath();
if (logger.isInfoEnabled()) {
logger.info("GraphQL endpoint WebSocket " + path);

View File

@@ -72,16 +72,16 @@ import static org.springframework.web.servlet.function.RequestPredicates.content
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(GraphQL.class)
@ConditionalOnBean(GraphQlSource.class)
@AutoConfigureAfter(GraphQlAutoConfiguration.class)
public class WebMvcGraphQlAutoConfiguration {
@AutoConfigureAfter(GraphQlServiceAutoConfiguration.class)
public class GraphQlWebMvcAutoConfiguration {
private static final Log logger = LogFactory.getLog(WebMvcGraphQlAutoConfiguration.class);
private static final Log logger = LogFactory.getLog(GraphQlWebMvcAutoConfiguration.class);
@Bean
@ConditionalOnBean(GraphQlService.class)
@ConditionalOnMissingBean
public WebGraphQlHandler webGraphQlHandler(ObjectProvider<WebInterceptor> interceptorsProvider,
GraphQlService service, ObjectProvider<ThreadLocalAccessor> accessorsProvider) {
public WebGraphQlHandler webGraphQlHandler(GraphQlService service, ObjectProvider<WebInterceptor> interceptorsProvider,
ObjectProvider<ThreadLocalAccessor> accessorsProvider) {
return WebGraphQlHandler.builder(service)
.interceptors(interceptorsProvider.orderedStream().collect(Collectors.toList()))
.threadLocalAccessors(accessorsProvider.orderedStream().collect(Collectors.toList())).build();
@@ -96,7 +96,6 @@ public class WebMvcGraphQlAutoConfiguration {
@Bean
public RouterFunction<ServerResponse> graphQlRouterFunction(GraphQlHttpHandler handler, GraphQlSource graphQlSource,
GraphQlProperties properties, ResourceLoader resourceLoader) {
String graphQLPath = properties.getPath();
if (logger.isInfoEnabled()) {
logger.info("GraphQL endpoint HTTP POST " + graphQLPath);
@@ -106,7 +105,7 @@ public class WebMvcGraphQlAutoConfiguration {
.POST(graphQLPath, contentType(MediaType.APPLICATION_JSON).and(accept(MediaType.APPLICATION_JSON)), handler::handleRequest);
if (properties.getGraphiql().isEnabled()) {
Resource resource = resourceLoader.getResource("classpath:graphiql/index.html");
WebMvcGraphiQlHandler graphiQLHandler = new WebMvcGraphiQlHandler(graphQLPath, resource);
GraphiQlWebMvcHandler graphiQLHandler = new GraphiQlWebMvcHandler(graphQLPath, resource);
builder = builder.GET(properties.getGraphiql().getPath(), graphiQLHandler::showGraphiQlPage);
}
if (properties.getSchema().getPrinter().isEnabled()) {
@@ -121,7 +120,7 @@ public class WebMvcGraphQlAutoConfiguration {
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ServerContainer.class, WebSocketHandler.class})
@ConditionalOnClass({ ServerContainer.class, WebSocketHandler.class })
@ConditionalOnProperty(prefix = "spring.graphql.websocket", name = "path")
public static class WebSocketConfiguration {
@@ -129,7 +128,6 @@ public class WebMvcGraphQlAutoConfiguration {
@ConditionalOnMissingBean
public GraphQlWebSocketHandler graphQlWebSocketHandler(WebGraphQlHandler webGraphQlHandler,
GraphQlProperties properties, HttpMessageConverters converters) {
// @formatter:off
HttpMessageConverter<?> converter = converters.getConverters().stream()
.filter((candidate) -> candidate.canRead(Map.class, MediaType.APPLICATION_JSON))

View File

@@ -25,20 +25,21 @@ import org.springframework.web.reactive.function.server.ServerResponse;
/**
* WebFlux functional handler for the GraphiQl UI.
*
* @author Brian Clozel
*/
class WebFluxGraphiQlHandler {
class GraphiQlWebFluxHandler {
private final String graphQlPath;
private final Resource graphiQlResource;
public WebFluxGraphiQlHandler(String graphQlPath, Resource graphiQlResource) {
GraphiQlWebFluxHandler(String graphQlPath, Resource graphiQlResource) {
this.graphQlPath = graphQlPath;
this.graphiQlResource = graphiQlResource;
}
public Mono<ServerResponse> showGraphiQlPage(ServerRequest request) {
Mono<ServerResponse> showGraphiQlPage(ServerRequest request) {
if (request.queryParam("path").isPresent()) {
return ServerResponse.ok().contentType(MediaType.TEXT_HTML).bodyValue(this.graphiQlResource);
}

View File

@@ -23,20 +23,21 @@ import org.springframework.web.servlet.function.ServerResponse;
/**
* Servlet.fn handler for the GraphiQl UI.
*
* @author Brian Clozel
*/
class WebMvcGraphiQlHandler {
class GraphiQlWebMvcHandler {
private final String graphQlPath;
private final Resource graphiQlResource;
public WebMvcGraphiQlHandler(String graphQlPath, Resource graphiQlResource) {
GraphiQlWebMvcHandler(String graphQlPath, Resource graphiQlResource) {
this.graphQlPath = graphQlPath;
this.graphiQlResource = graphiQlResource;
}
public ServerResponse showGraphiQlPage(ServerRequest request) {
ServerResponse showGraphiQlPage(ServerRequest request) {
if (request.param("path").isPresent()) {
return ServerResponse.ok().contentType(MediaType.TEXT_HTML).body(this.graphiQlResource);
}
@@ -44,4 +45,5 @@ class WebMvcGraphiQlHandler {
return ServerResponse.temporaryRedirect(request.uriBuilder().queryParam("path", this.graphQlPath).build()).build();
}
}
}

View File

@@ -19,18 +19,19 @@ package org.springframework.graphql.boot;
import graphql.schema.idl.RuntimeWiring;
/**
* Callback interface that can be used to customize the GraphQL
* {@link RuntimeWiring.Builder}.
* Callback interface that can be implemented by beans wishing to customize the
* {@link RuntimeWiring} via a {@link RuntimeWiring.Builder} whilst retaining default
* auto-configuration.
*
* @author Brian Clozel
* @since 1.0.0
*/
@FunctionalInterface
public interface RuntimeWiringCustomizer {
public interface RuntimeWiringBuilderCustomizer {
/**
* Callback to customize a {@link RuntimeWiring.Builder} instance.
* @param builder builder instance to customize
* Customize the {@link RuntimeWiring.Builder} instance.
* @param builder builder the builder to customize
*/
void customize(RuntimeWiring.Builder builder);

View File

@@ -2,12 +2,14 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.graphql.boot.actuate.metrics.GraphQlMetricsAutoConfiguration,\
org.springframework.graphql.boot.GraphQlAutoConfiguration,\
org.springframework.graphql.boot.GraphQlServiceAutoConfiguration,\
org.springframework.graphql.boot.WebFluxGraphQlAutoConfiguration,\
org.springframework.graphql.boot.WebMvcGraphQlAutoConfiguration
org.springframework.graphql.boot.GraphQlWebFluxAutoConfiguration,\
org.springframework.graphql.boot.GraphQlWebMvcAutoConfiguration
# Spring Test @AutoConfigureGraphQlTester
org.springframework.graphql.boot.test.tester.AutoConfigureGraphQlTester=\
org.springframework.graphql.boot.test.tester.WebTestClientMockMvcAutoConfiguration,\
org.springframework.graphql.boot.test.tester.GraphQlTesterAutoConfiguration
# Spring Test ContextCustomizerFactories
org.springframework.test.context.ContextCustomizerFactory=\
org.springframework.graphql.boot.test.tester.GraphQlTesterContextCustomizerFactory

View File

@@ -27,9 +27,7 @@ import org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration;
import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration;
import org.springframework.boot.test.context.runner.ContextConsumer;
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.graphql.web.WebInterceptor;
@@ -40,15 +38,20 @@ import static org.hamcrest.Matchers.containsString;
// @formatter:off
class WebFluxApplicationContextTests {
private static final AutoConfigurations AUTO_CONFIGURATIONS = AutoConfigurations.of(
HttpHandlerAutoConfiguration.class, WebFluxAutoConfiguration.class, CodecsAutoConfiguration.class,
JacksonAutoConfiguration.class, GraphQlAutoConfiguration.class, GraphQlServiceAutoConfiguration.class,
WebFluxGraphQlAutoConfiguration.class);
class GraphQlWebFluxAutoConfigurationTests {
private static final String BASE_URL = "https://spring.example.org/graphql";
private final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(HttpHandlerAutoConfiguration.class, WebFluxAutoConfiguration.class,
CodecsAutoConfiguration.class, JacksonAutoConfiguration.class, GraphQlAutoConfiguration.class,
GraphQlServiceAutoConfiguration.class, GraphQlWebFluxAutoConfiguration.class))
.withUserConfiguration(DataFetchersConfiguration.class, CustomWebInterceptor.class)
.withPropertyValues(
"spring.main.web-application-type=reactive",
"spring.graphql.schema.printer.enabled=true",
"spring.graphql.schema.locations=classpath:books/");
@Test
void query() {
testWithWebClient((client) -> {
@@ -56,7 +59,7 @@ class WebFluxApplicationContextTests {
" bookById(id: \\\"book-1\\\"){ " +
" id" +
" name" +
" pageCount" +
" pageCount" +
" author" +
" }" +
"}";
@@ -124,7 +127,7 @@ class WebFluxApplicationContextTests {
}
private void testWithWebClient(Consumer<WebTestClient> consumer) {
testWithApplicationContext((context) -> {
this.contextRunner.run((context) -> {
WebTestClient client = WebTestClient.bindToApplicationContext(context)
.configureClient()
.defaultHeaders((headers) -> {
@@ -137,22 +140,11 @@ class WebFluxApplicationContextTests {
});
}
private void testWithApplicationContext(ContextConsumer<ApplicationContext> consumer) {
new ReactiveWebApplicationContextRunner()
.withConfiguration(AUTO_CONFIGURATIONS)
.withUserConfiguration(DataFetchersConfiguration.class, CustomWebInterceptor.class)
.withPropertyValues(
"spring.main.web-application-type=reactive",
"spring.graphql.schema.printer.enabled=true",
"spring.graphql.schema.locations=classpath:books/")
.run(consumer);
}
@Configuration(proxyBeanMethods = false)
public static class DataFetchersConfiguration {
static class DataFetchersConfiguration {
@Bean
public RuntimeWiringCustomizer bookDataFetcher() {
RuntimeWiringBuilderCustomizer bookDataFetcher() {
return (runtimeWiring) ->
runtimeWiring.type(TypeRuntimeWiring.newTypeWiring("Query")
.dataFetcher("bookById", GraphQlDataFetchers.getBookByIdDataFetcher()));
@@ -161,10 +153,10 @@ class WebFluxApplicationContextTests {
}
@Configuration(proxyBeanMethods = false)
public static class CustomWebInterceptor {
static class CustomWebInterceptor {
@Bean
public WebInterceptor customWebInterceptor() {
WebInterceptor customWebInterceptor() {
return (input, next) -> next.handle(input).map((output) ->
output.transform((builder) -> builder.responseHeader("X-Custom-Header", "42")));
}

View File

@@ -44,13 +44,18 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
// @formatter:off
class WebMvcApplicationContextTests {
class GraphQlWebMvcAutoConfigurationTests {
public static final AutoConfigurations AUTO_CONFIGURATIONS = AutoConfigurations.of(
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class, JacksonAutoConfiguration.class,
GraphQlAutoConfiguration.class, GraphQlServiceAutoConfiguration.class,
WebMvcGraphQlAutoConfiguration.class);
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(DispatcherServletAutoConfiguration.class,
WebMvcAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
JacksonAutoConfiguration.class, GraphQlAutoConfiguration.class,
GraphQlServiceAutoConfiguration.class, GraphQlWebMvcAutoConfiguration.class))
.withUserConfiguration(DataFetchersConfiguration.class, CustomWebInterceptor.class)
.withPropertyValues(
"spring.main.web-application-type=servlet",
"spring.graphql.schema.printer.enabled=true",
"spring.graphql.schema.locations=classpath:books/");
@Test
void endpointHandlesGraphQlQuery() {
@@ -108,20 +113,13 @@ class WebMvcApplicationContextTests {
}
private void testWith(MockMvcConsumer mockMvcConsumer) {
new WebApplicationContextRunner()
.withConfiguration(AUTO_CONFIGURATIONS)
.withUserConfiguration(DataFetchersConfiguration.class, CustomWebInterceptor.class)
.withPropertyValues(
"spring.main.web-application-type=servlet",
"spring.graphql.schema.printer.enabled=true",
"spring.graphql.schema.locations=classpath:books/")
.run((context) -> {
MediaType mediaType = MediaType.APPLICATION_JSON;
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context)
.defaultRequest(post("/graphql").contentType(mediaType).accept(mediaType))
.build();
mockMvcConsumer.accept(mockMvc);
});
this.contextRunner.run((context) -> {
MediaType mediaType = MediaType.APPLICATION_JSON;
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context)
.defaultRequest(post("/graphql").contentType(mediaType).accept(mediaType))
.build();
mockMvcConsumer.accept(mockMvc);
});
}
private interface MockMvcConsumer {
@@ -131,10 +129,10 @@ class WebMvcApplicationContextTests {
}
@Configuration(proxyBeanMethods = false)
public static class DataFetchersConfiguration {
static class DataFetchersConfiguration {
@Bean
public RuntimeWiringCustomizer bookDataFetcher() {
RuntimeWiringBuilderCustomizer bookDataFetcher() {
return (builder) -> builder.type(TypeRuntimeWiring.newTypeWiring("Query")
.dataFetcher("bookById", GraphQlDataFetchers.getBookByIdDataFetcher()));
}
@@ -142,10 +140,10 @@ class WebMvcApplicationContextTests {
}
@Configuration(proxyBeanMethods = false)
public static class CustomWebInterceptor {
static class CustomWebInterceptor {
@Bean
public WebInterceptor customWebInterceptor() {
WebInterceptor customWebInterceptor() {
return (input, next) -> next.handle(input).map((output) ->
output.transform((builder) -> builder.responseHeader("X-Custom-Header", "42")));
}

View File

@@ -20,11 +20,11 @@ import java.util.Map;
import graphql.schema.idl.RuntimeWiring;
import org.springframework.graphql.boot.RuntimeWiringCustomizer;
import org.springframework.graphql.boot.RuntimeWiringBuilderCustomizer;
import org.springframework.stereotype.Component;
@Component
public class SampleWiring implements RuntimeWiringCustomizer {
public class SampleWiring implements RuntimeWiringBuilderCustomizer {
final EmployeeService employeeService;

View File

@@ -18,11 +18,11 @@ package io.spring.sample.graphql;
import graphql.schema.idl.RuntimeWiring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.graphql.boot.RuntimeWiringCustomizer;
import org.springframework.graphql.boot.RuntimeWiringBuilderCustomizer;
import org.springframework.stereotype.Component;
@Component
public class SampleWiring implements RuntimeWiringCustomizer {
public class SampleWiring implements RuntimeWiringBuilderCustomizer {
private final DataRepository repository;

View File

@@ -5,11 +5,11 @@ import java.util.Map;
import graphql.schema.idl.RuntimeWiring;
import org.springframework.graphql.boot.RuntimeWiringCustomizer;
import org.springframework.graphql.boot.RuntimeWiringBuilderCustomizer;
import org.springframework.stereotype.Component;
@Component
public class SampleWiring implements RuntimeWiringCustomizer {
public class SampleWiring implements RuntimeWiringBuilderCustomizer {
final EmployeeService employeeService;

View File

@@ -2,7 +2,7 @@ package io.spring.sample.graphql.greeting;
import graphql.schema.idl.RuntimeWiring;
import org.springframework.graphql.boot.RuntimeWiringCustomizer;
import org.springframework.graphql.boot.RuntimeWiringBuilderCustomizer;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
@@ -10,7 +10,7 @@ import org.springframework.web.context.request.RequestContextHolder;
import static org.springframework.web.context.request.RequestAttributes.SCOPE_REQUEST;
@Component
public class GreetingDataWiring implements RuntimeWiringCustomizer {
public class GreetingDataWiring implements RuntimeWiringBuilderCustomizer {
@Override
public void customize(RuntimeWiring.Builder builder) {

View File

@@ -1,11 +1,11 @@
package io.spring.sample.graphql.project;
import graphql.schema.idl.RuntimeWiring;
import org.springframework.graphql.boot.RuntimeWiringCustomizer;
import org.springframework.graphql.boot.RuntimeWiringBuilderCustomizer;
import org.springframework.stereotype.Component;
@Component
public class ProjectDataWiring implements RuntimeWiringCustomizer {
public class ProjectDataWiring implements RuntimeWiringBuilderCustomizer {
private final SpringProjectsClient client;

View File

@@ -2,12 +2,12 @@ package io.spring.sample.graphql.repository;
import graphql.schema.idl.RuntimeWiring;
import org.springframework.graphql.boot.RuntimeWiringCustomizer;
import org.springframework.graphql.boot.RuntimeWiringBuilderCustomizer;
import org.springframework.graphql.data.QuerydslDataFetcher;
import org.springframework.stereotype.Component;
@Component
public class ArtifactRepositoryDataWiring implements RuntimeWiringCustomizer {
public class ArtifactRepositoryDataWiring implements RuntimeWiringBuilderCustomizer {
private final ArtifactRepositories repositories;