diff --git a/graphql-spring-boot-starter/build.gradle b/graphql-spring-boot-starter/build.gradle index 24f6cef6..73b62d05 100644 --- a/graphql-spring-boot-starter/build.gradle +++ b/graphql-spring-boot-starter/build.gradle @@ -4,6 +4,7 @@ plugins { id 'org.springframework.boot' version '2.4.5' apply false id 'io.spring.dependency-management' version '1.0.10.RELEASE' id 'java-library' + id "org.springframework.graphql.conventions" } description = "GraphQL Spring Boot Starter" 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 cd90a57f..1fb95faa 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 @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.graphql.boot; import java.util.stream.Collectors; @@ -22,6 +23,7 @@ import graphql.execution.instrumentation.Instrumentation; import graphql.schema.idl.RuntimeWiring; import org.springframework.beans.factory.ObjectProvider; +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; @@ -31,7 +33,14 @@ import org.springframework.core.io.ResourceLoader; import org.springframework.graphql.execution.DataFetcherExceptionResolver; import org.springframework.graphql.execution.GraphQlSource; -@Configuration +/** + * {@link EnableAutoConfiguration Auto-configuration} for creating a + * {@link GraphQlSource}. + * + * @author Brian Clozel + * @since 1.0.0 + */ +@Configuration(proxyBeanMethods = false) @ConditionalOnClass(GraphQL.class) @ConditionalOnMissingBean(GraphQlSource.class) @EnableConfigurationProperties(GraphQlProperties.class) @@ -42,31 +51,30 @@ public class GraphQlAutoConfiguration { return builder.build(); } - @Configuration + @Configuration(proxyBeanMethods = false) @ConditionalOnMissingBean(GraphQlSource.Builder.class) - static class GraphQlSourceConfiguration { + public static class GraphQlSourceConfiguration { @Bean @ConditionalOnMissingBean public RuntimeWiring runtimeWiring(ObjectProvider customizers) { RuntimeWiring.Builder builder = RuntimeWiring.newRuntimeWiring(); - customizers.orderedStream().forEach(customizer -> customizer.customize(builder)); + customizers.orderedStream().forEach((customizer) -> customizer.customize(builder)); return builder.build(); } @Bean - public GraphQlSource.Builder graphQlSourceBuilder( - GraphQlProperties properties, RuntimeWiring runtimeWiring, - ObjectProvider exceptionResolversProvider, - ResourceLoader resourceLoader, ObjectProvider instrumentationsProvider) { + public GraphQlSource.Builder graphQlSourceBuilder(GraphQlProperties properties, RuntimeWiring runtimeWiring, + ObjectProvider exceptionResolversProvider, ResourceLoader resourceLoader, + ObjectProvider instrumentationsProvider) { String schemaLocation = properties.getSchema().getLocation(); - return GraphQlSource.builder() - .schemaResource(resourceLoader.getResource(schemaLocation)) + return GraphQlSource.builder().schemaResource(resourceLoader.getResource(schemaLocation)) .runtimeWiring(runtimeWiring) .exceptionResolvers(exceptionResolversProvider.orderedStream().collect(Collectors.toList())) .instrumentation(instrumentationsProvider.orderedStream().collect(Collectors.toList())); } + } } diff --git a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/GraphQlProperties.java b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/GraphQlProperties.java index 30753a8f..07a0bb60 100644 --- a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/GraphQlProperties.java +++ b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/GraphQlProperties.java @@ -13,12 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.graphql.boot; import java.time.Duration; import org.springframework.boot.context.properties.ConfigurationProperties; +/** + * {@link ConfigurationProperties properties} for Spring GraphQL. + * + * @author Brian Clozel + * @since 1.0.0 + */ @ConfigurationProperties(prefix = "spring.graphql") public class GraphQlProperties { @@ -68,7 +75,6 @@ public class GraphQlProperties { return this.printer; } - public static class Printer { /** @@ -96,11 +102,11 @@ public class GraphQlProperties { public void setPath(String path) { this.path = path; } + } } - public static class WebSocket { /** @@ -109,7 +115,8 @@ public class GraphQlProperties { private String path; /** - * Time within which the initial {@code CONNECTION_INIT} type message must be received. + * Time within which the initial {@code CONNECTION_INIT} type message must be + * received. */ private Duration connectionInitTimeout = Duration.ofSeconds(60); @@ -128,5 +135,7 @@ public class GraphQlProperties { public void setConnectionInitTimeout(Duration connectionInitTimeout) { this.connectionInitTimeout = connectionInitTimeout; } + } + } diff --git a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/GraphQlServiceAutoConfiguration.java b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/GraphQlServiceAutoConfiguration.java index 0a7e00f1..79581d49 100644 --- a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/GraphQlServiceAutoConfiguration.java +++ b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/GraphQlServiceAutoConfiguration.java @@ -13,11 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.graphql.boot; import graphql.GraphQL; import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; @@ -26,7 +28,14 @@ import org.springframework.graphql.GraphQlService; import org.springframework.graphql.execution.ExecutionGraphQlService; import org.springframework.graphql.execution.GraphQlSource; -@Configuration +/** + * {@link EnableAutoConfiguration Auto-configuration} for creating a + * {@link GraphQlService}. + * + * @author Brian Clozel + * @since 1.0.0 + */ +@Configuration(proxyBeanMethods = false) @ConditionalOnClass(GraphQL.class) @ConditionalOnMissingBean(GraphQlService.class) @AutoConfigureAfter(GraphQlAutoConfiguration.class) diff --git a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/RuntimeWiringCustomizer.java b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/RuntimeWiringCustomizer.java index 67fc0e49..f18e53fc 100644 --- a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/RuntimeWiringCustomizer.java +++ b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/RuntimeWiringCustomizer.java @@ -13,13 +13,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.graphql.boot; import graphql.schema.idl.RuntimeWiring; +/** + * Callback interface that can be used to customize the GraphQL + * {@link RuntimeWiring.Builder}. + * + * @author Brian Clozel + * @since 1.0.0 + */ @FunctionalInterface public interface RuntimeWiringCustomizer { + /** + * Callback to customize a {@link RuntimeWiring.Builder} instance. + * @param builder builder instance to customize + */ void customize(RuntimeWiring.Builder builder); } diff --git a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/WebFluxGraphQlAutoConfiguration.java b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/WebFluxGraphQlAutoConfiguration.java index 19139ea2..1a7ec1a2 100644 --- a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/WebFluxGraphQlAutoConfiguration.java +++ b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/WebFluxGraphQlAutoConfiguration.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.graphql.boot; import java.util.Collections; @@ -25,6 +26,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -43,16 +45,21 @@ import org.springframework.graphql.web.webflux.GraphQlWebSocketHandler; import org.springframework.http.MediaType; import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.web.reactive.HandlerMapping; +import org.springframework.web.reactive.function.server.RequestPredicates; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.RouterFunctions; import org.springframework.web.reactive.function.server.ServerResponse; import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping; import org.springframework.web.reactive.socket.server.support.WebSocketUpgradeHandlerPredicate; -import static org.springframework.web.reactive.function.server.RequestPredicates.accept; -import static org.springframework.web.reactive.function.server.RequestPredicates.contentType; - -@Configuration +/** + * {@link EnableAutoConfiguration Auto-configuration} for enabling Spring GraphQL over + * WebFlux. + * + * @author Brian Clozel + * @since 1.0.0 + */ +@Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) @ConditionalOnClass(GraphQL.class) @ConditionalOnBean(GraphQlSource.class) @@ -61,13 +68,11 @@ public class WebFluxGraphQlAutoConfiguration { private static final Log logger = LogFactory.getLog(WebFluxGraphQlAutoConfiguration.class); - @Bean @ConditionalOnMissingBean public WebGraphQlHandler webGraphQlHandler(ObjectProvider interceptors, GraphQlService service) { return WebGraphQlHandler.builder(service) - .interceptors(interceptors.orderedStream().collect(Collectors.toList())) - .build(); + .interceptors(interceptors.orderedStream().collect(Collectors.toList())).build(); } @Bean @@ -86,33 +91,33 @@ public class WebFluxGraphQlAutoConfiguration { logger.info("GraphQL endpoint HTTP POST " + path); } RouterFunctions.Builder builder = RouterFunctions.route() - .GET(path, req -> ServerResponse.ok().bodyValue(resource)) - .POST(path, accept(MediaType.APPLICATION_JSON).and(contentType(MediaType.APPLICATION_JSON)), handler::handleRequest); + .GET(path, (req) -> ServerResponse.ok().bodyValue(resource)) + .POST(path, RequestPredicates.accept(MediaType.APPLICATION_JSON) + .and(RequestPredicates.contentType(MediaType.APPLICATION_JSON)), handler::handleRequest); if (properties.getSchema().getPrinter().isEnabled()) { SchemaPrinter printer = new SchemaPrinter(); - builder = builder.GET(path + properties.getSchema().getPrinter().getPath(), - req -> ServerResponse.ok() - .contentType(MediaType.TEXT_PLAIN) - .bodyValue(printer.print(graphQlSource.schema()))); + builder = builder.GET(path + properties.getSchema().getPrinter().getPath(), (req) -> ServerResponse.ok() + .contentType(MediaType.TEXT_PLAIN).bodyValue(printer.print(graphQlSource.schema()))); } return builder.build(); } + @Configuration(proxyBeanMethods = false) @ConditionalOnProperty(prefix = "spring.graphql.websocket", name = "path") - static class WebSocketConfiguration { + public static class WebSocketConfiguration { @Bean @ConditionalOnMissingBean - public GraphQlWebSocketHandler graphQlWebSocketHandler( - WebGraphQlHandler webGraphQlHandler, GraphQlProperties properties, ServerCodecConfigurer configurer) { + public GraphQlWebSocketHandler graphQlWebSocketHandler(WebGraphQlHandler webGraphQlHandler, + GraphQlProperties properties, ServerCodecConfigurer configurer) { - return new GraphQlWebSocketHandler( - webGraphQlHandler, configurer, properties.getWebsocket().getConnectionInitTimeout()); + return new GraphQlWebSocketHandler(webGraphQlHandler, configurer, + properties.getWebsocket().getConnectionInitTimeout()); } @Bean - public HandlerMapping graphQlWebSocketEndpoint( - GraphQlWebSocketHandler graphQlWebSocketHandler, GraphQlProperties properties) { + public HandlerMapping graphQlWebSocketEndpoint(GraphQlWebSocketHandler graphQlWebSocketHandler, + GraphQlProperties properties) { String path = properties.getWebsocket().getPath(); if (logger.isInfoEnabled()) { @@ -124,6 +129,7 @@ public class WebFluxGraphQlAutoConfiguration { mapping.setOrder(-2); // Ahead of HTTP endpoint ("routerFunctionMapping" bean) return mapping; } + } } diff --git a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/WebMvcGraphQlAutoConfiguration.java b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/WebMvcGraphQlAutoConfiguration.java index 0d37d8be..992a3a84 100644 --- a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/WebMvcGraphQlAutoConfiguration.java +++ b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/WebMvcGraphQlAutoConfiguration.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.graphql.boot; import java.util.Collections; @@ -28,6 +29,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -48,6 +50,7 @@ import org.springframework.graphql.web.webmvc.GraphQlWebSocketHandler; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.web.servlet.HandlerMapping; +import org.springframework.web.servlet.function.RequestPredicates; import org.springframework.web.servlet.function.RouterFunction; import org.springframework.web.servlet.function.RouterFunctions; import org.springframework.web.servlet.function.ServerResponse; @@ -56,10 +59,14 @@ import org.springframework.web.socket.server.support.DefaultHandshakeHandler; import org.springframework.web.socket.server.support.WebSocketHandlerMapping; import org.springframework.web.socket.server.support.WebSocketHttpRequestHandler; -import static org.springframework.web.servlet.function.RequestPredicates.accept; -import static org.springframework.web.servlet.function.RequestPredicates.contentType; - -@Configuration +/** + * {@link EnableAutoConfiguration Auto-configuration} for enabling Spring GraphQL over + * Spring MVC. + * + * @author Brian Clozel + * @since 1.0.0 + */ +@Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) @ConditionalOnClass(GraphQL.class) @ConditionalOnBean(GraphQlSource.class) @@ -68,17 +75,14 @@ public class WebMvcGraphQlAutoConfiguration { private static final Log logger = LogFactory.getLog(WebMvcGraphQlAutoConfiguration.class); - @Bean @ConditionalOnMissingBean - public WebGraphQlHandler webGraphQlHandler( - ObjectProvider interceptorsProvider, GraphQlService service, - ObjectProvider accessorsProvider) { + public WebGraphQlHandler webGraphQlHandler(ObjectProvider interceptorsProvider, + GraphQlService service, ObjectProvider accessorsProvider) { return WebGraphQlHandler.builder(service) .interceptors(interceptorsProvider.orderedStream().collect(Collectors.toList())) - .threadLocalAccessors(accessorsProvider.orderedStream().collect(Collectors.toList())) - .build(); + .threadLocalAccessors(accessorsProvider.orderedStream().collect(Collectors.toList())).build(); } @Bean @@ -96,36 +100,33 @@ public class WebMvcGraphQlAutoConfiguration { if (logger.isInfoEnabled()) { logger.info("GraphQL endpoint HTTP POST " + path); } - RouterFunctions.Builder builder = RouterFunctions.route() - .GET(path, req -> ServerResponse.ok().body(resource)) - .POST(path, contentType(MediaType.APPLICATION_JSON).and(accept(MediaType.APPLICATION_JSON)), handler::handleRequest); + RouterFunctions.Builder builder = RouterFunctions.route().GET(path, (req) -> ServerResponse.ok().body(resource)) + .POST(path, RequestPredicates.contentType(MediaType.APPLICATION_JSON) + .and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), handler::handleRequest); if (properties.getSchema().getPrinter().isEnabled()) { SchemaPrinter printer = new SchemaPrinter(); - builder = builder.GET(path + properties.getSchema().getPrinter().getPath(), - req -> ServerResponse.ok() - .contentType(MediaType.TEXT_PLAIN) - .body(printer.print(graphQlSource.schema()))); + builder = builder.GET(path + properties.getSchema().getPrinter().getPath(), (req) -> ServerResponse.ok() + .contentType(MediaType.TEXT_PLAIN).body(printer.print(graphQlSource.schema()))); } return builder.build(); } - - @ConditionalOnClass({ServerContainer.class, WebSocketHandler.class}) + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass({ ServerContainer.class, WebSocketHandler.class }) @ConditionalOnProperty(prefix = "spring.graphql.websocket", name = "path") - static class WebSocketConfiguration { + public static class WebSocketConfiguration { @Bean @ConditionalOnMissingBean - public GraphQlWebSocketHandler graphQlWebSocketHandler( - WebGraphQlHandler webGraphQlHandler, GraphQlProperties properties, HttpMessageConverters converters) { + public GraphQlWebSocketHandler graphQlWebSocketHandler(WebGraphQlHandler webGraphQlHandler, + GraphQlProperties properties, HttpMessageConverters converters) { HttpMessageConverter converter = converters.getConverters().stream() - .filter(candidate -> candidate.canRead(Map.class, MediaType.APPLICATION_JSON)) - .findFirst() + .filter((candidate) -> candidate.canRead(Map.class, MediaType.APPLICATION_JSON)).findFirst() .orElseThrow(() -> new IllegalStateException("No JSON converter")); - return new GraphQlWebSocketHandler( - webGraphQlHandler, converter, properties.getWebsocket().getConnectionInitTimeout()); + return new GraphQlWebSocketHandler(webGraphQlHandler, converter, + properties.getWebsocket().getConnectionInitTimeout()); } @Bean @@ -144,6 +145,4 @@ public class WebMvcGraphQlAutoConfiguration { } - - } diff --git a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/DefaultGraphQlTagsProvider.java b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/DefaultGraphQlTagsProvider.java index c47c4b8c..d8946e26 100644 --- a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/DefaultGraphQlTagsProvider.java +++ b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/DefaultGraphQlTagsProvider.java @@ -26,6 +26,12 @@ import graphql.schema.DataFetcher; import io.micrometer.core.instrument.Tag; import io.micrometer.core.instrument.Tags; +/** + * Default implementation for {@link GraphQlTagsProvider}. + * + * @author Brian Clozel + * @since 1.0.0 + */ public class DefaultGraphQlTagsProvider implements GraphQlTagsProvider { private final List contributors; @@ -34,9 +40,9 @@ public class DefaultGraphQlTagsProvider implements GraphQlTagsProvider { this.contributors = contributors; } - @Override - public Iterable getExecutionTags(InstrumentationExecutionParameters parameters, ExecutionResult result, Throwable exception) { + public Iterable getExecutionTags(InstrumentationExecutionParameters parameters, ExecutionResult result, + Throwable exception) { Tags tags = Tags.of(GraphQlTags.executionOutcome(result, exception)); for (GraphQlTagsContributor contributor : this.contributors) { tags = tags.and(contributor.getExecutionTags(parameters, result, exception)); @@ -54,11 +60,13 @@ public class DefaultGraphQlTagsProvider implements GraphQlTagsProvider { } @Override - public Iterable getDataFetchingTags(DataFetcher dataFetcher, InstrumentationFieldFetchParameters parameters, Throwable exception) { + public Iterable getDataFetchingTags(DataFetcher dataFetcher, InstrumentationFieldFetchParameters parameters, + Throwable exception) { Tags tags = Tags.of(GraphQlTags.dataFetchingOutcome(exception), GraphQlTags.dataFetchingPath(parameters)); for (GraphQlTagsContributor contributor : this.contributors) { tags = tags.and(contributor.getDataFetchingTags(dataFetcher, parameters, exception)); } return tags; } + } diff --git a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/GraphQlMetricsAutoConfiguration.java b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/GraphQlMetricsAutoConfiguration.java index 9e843d1c..44902669 100644 --- a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/GraphQlMetricsAutoConfiguration.java +++ b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/GraphQlMetricsAutoConfiguration.java @@ -33,12 +33,15 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** - * {@link EnableAutoConfiguration Auto-configuration} for instrumentation of Spring GraphQL - * endpoints. + * {@link EnableAutoConfiguration Auto-configuration} for instrumentation of Spring + * GraphQL endpoints. + * + * @author Brian Clozel + * @since 1.0.0 */ @Configuration(proxyBeanMethods = false) -@AutoConfigureAfter({MetricsAutoConfiguration.class, CompositeMeterRegistryAutoConfiguration.class, - SimpleMetricsExportAutoConfiguration.class}) +@AutoConfigureAfter({ MetricsAutoConfiguration.class, CompositeMeterRegistryAutoConfiguration.class, + SimpleMetricsExportAutoConfiguration.class }) @ConditionalOnBean(MeterRegistry.class) @EnableConfigurationProperties(GraphQlMetricsProperties.class) public class GraphQlMetricsAutoConfiguration { @@ -54,4 +57,5 @@ public class GraphQlMetricsAutoConfiguration { GraphQlTagsProvider tagsProvider, GraphQlMetricsProperties properties) { return new GraphQlMetricsInstrumentation(meterRegistry, tagsProvider, properties.getAutotime()); } + } diff --git a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/GraphQlMetricsInstrumentation.java b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/GraphQlMetricsInstrumentation.java index c7660c6f..06747ff0 100644 --- a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/GraphQlMetricsInstrumentation.java +++ b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/GraphQlMetricsInstrumentation.java @@ -31,8 +31,9 @@ import io.micrometer.core.instrument.Tag; import io.micrometer.core.instrument.Timer; import org.springframework.boot.actuate.metrics.AutoTimer; +import org.springframework.lang.Nullable; -public class GraphQlMetricsInstrumentation extends SimpleInstrumentation { +class GraphQlMetricsInstrumentation extends SimpleInstrumentation { private final MeterRegistry registry; @@ -40,7 +41,7 @@ public class GraphQlMetricsInstrumentation extends SimpleInstrumentation { private final AutoTimer autoTimer; - public GraphQlMetricsInstrumentation(MeterRegistry registry, GraphQlTagsProvider tagsProvider, AutoTimer autoTimer) { + GraphQlMetricsInstrumentation(MeterRegistry registry, GraphQlTagsProvider tagsProvider, AutoTimer autoTimer) { this.registry = registry; this.tagsProvider = tagsProvider; this.autoTimer = autoTimer; @@ -59,12 +60,14 @@ public class GraphQlMetricsInstrumentation extends SimpleInstrumentation { return new SimpleInstrumentationContext() { @Override public void onCompleted(ExecutionResult result, Throwable exc) { - Iterable tags = tagsProvider.getExecutionTags(parameters, result, exc); + Iterable tags = GraphQlMetricsInstrumentation.this.tagsProvider.getExecutionTags(parameters, + result, exc); state.tags(tags).stopTimer(); if (!result.getErrors().isEmpty()) { - result.getErrors().forEach(error -> { - registry.counter("graphql.error", tagsProvider.getErrorTags(parameters, error)).increment(); - }); + result.getErrors() + .forEach((error) -> GraphQlMetricsInstrumentation.this.registry.counter("graphql.error", + GraphQlMetricsInstrumentation.this.tagsProvider.getErrorTags(parameters, error)) + .increment()); } } }; @@ -73,7 +76,8 @@ public class GraphQlMetricsInstrumentation extends SimpleInstrumentation { } @Override - public DataFetcher instrumentDataFetcher(DataFetcher dataFetcher, InstrumentationFieldFetchParameters parameters) { + public DataFetcher instrumentDataFetcher(DataFetcher dataFetcher, + InstrumentationFieldFetchParameters parameters) { if (this.autoTimer.isEnabled() && !parameters.isTrivialDataFetcher()) { return (environment) -> { Timer.Sample sample = Timer.start(this.registry); @@ -81,9 +85,8 @@ public class GraphQlMetricsInstrumentation extends SimpleInstrumentation { Object value = dataFetcher.get(environment); if (value instanceof CompletionStage) { CompletionStage completion = (CompletionStage) value; - return completion.whenComplete((result, error) -> { - recordDataFetcherMetric(sample, dataFetcher, parameters, error); - }); + return completion.whenComplete( + (result, error) -> recordDataFetcherMetric(sample, dataFetcher, parameters, error)); } else { recordDataFetcherMetric(sample, dataFetcher, parameters, null); @@ -100,13 +103,13 @@ public class GraphQlMetricsInstrumentation extends SimpleInstrumentation { return super.instrumentDataFetcher(dataFetcher, parameters); } - private void recordDataFetcherMetric(Timer.Sample sample, DataFetcher dataFetcher, InstrumentationFieldFetchParameters parameters, Throwable throwable) { + private void recordDataFetcherMetric(Timer.Sample sample, DataFetcher dataFetcher, + InstrumentationFieldFetchParameters parameters, @Nullable Throwable throwable) { Timer.Builder timer = this.autoTimer.builder("graphql.datafetcher"); timer.tags(this.tagsProvider.getDataFetchingTags(dataFetcher, parameters, throwable)); sample.stop(timer.register(this.registry)); } - static class RequestMetricsInstrumentationState implements InstrumentationState { private final MeterRegistry registry; @@ -120,18 +123,19 @@ public class GraphQlMetricsInstrumentation extends SimpleInstrumentation { this.registry = registry; } - public RequestMetricsInstrumentationState tags(Iterable tags) { + RequestMetricsInstrumentationState tags(Iterable tags) { this.timer.tags(tags); return this; } - public void startTimer() { + void startTimer() { this.sample = Timer.start(this.registry); } - public void stopTimer() { + void stopTimer() { this.sample.stop(this.timer.register(this.registry)); } + } } diff --git a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/GraphQlMetricsProperties.java b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/GraphQlMetricsProperties.java index 27f0974d..0f1c923b 100644 --- a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/GraphQlMetricsProperties.java +++ b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/GraphQlMetricsProperties.java @@ -21,7 +21,13 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.NestedConfigurationProperty; /** - * This class could be merged with {@link org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties} + * {@link ConfigurationProperties properties} for Spring GraphQL. + *

+ * This class could be later merged with + * {@link org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties}. + * + * @author Brian Clozel + * @since 1.0.0 */ @ConfigurationProperties("management.metrics.graphql") public class GraphQlMetricsProperties { @@ -35,4 +41,5 @@ public class GraphQlMetricsProperties { public AutoTimeProperties getAutotime() { return this.autotime; } + } diff --git a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/GraphQlTags.java b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/GraphQlTags.java index 5849e81f..404bc965 100644 --- a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/GraphQlTags.java +++ b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/GraphQlTags.java @@ -27,12 +27,14 @@ import graphql.execution.instrumentation.parameters.InstrumentationFieldFetchPar import graphql.schema.GraphQLObjectType; import io.micrometer.core.instrument.Tag; +import org.springframework.lang.Nullable; import org.springframework.util.CollectionUtils; /** - * Factory methods for Tags associated with a GraphQL requests. - * + * Factory methods for Tags associated with a GraphQL request. + * * @author Brian Clozel + * @since 1.0.0 */ public final class GraphQlTags { @@ -42,7 +44,11 @@ public final class GraphQlTags { private static final Tag UNKNOWN_ERRORTYPE = Tag.of("errorType", "UNKNOWN"); - public static Tag executionOutcome(ExecutionResult result, Throwable exception) { + private GraphQlTags() { + + } + + public static Tag executionOutcome(ExecutionResult result, @Nullable Throwable exception) { if (exception == null && result.getErrors().isEmpty()) { return OUTCOME_SUCCESS; } @@ -78,19 +84,19 @@ public final class GraphQlTags { return Tag.of("errorPath", builder.toString()); } - public static Tag dataFetchingOutcome(Throwable exception) { - return (exception == null) ? OUTCOME_SUCCESS : OUTCOME_ERROR; + public static Tag dataFetchingOutcome(@Nullable Throwable exception) { + return (exception != null) ? OUTCOME_ERROR : OUTCOME_SUCCESS; } public static Tag dataFetchingPath(InstrumentationFieldFetchParameters parameters) { ExecutionStepInfo executionStepInfo = parameters.getExecutionStepInfo(); StringBuilder dataFetchingType = new StringBuilder(); - if (executionStepInfo.hasParent() && - executionStepInfo.getParent().getType() instanceof GraphQLObjectType) { + if (executionStepInfo.hasParent() && executionStepInfo.getParent().getType() instanceof GraphQLObjectType) { dataFetchingType.append(((GraphQLObjectType) executionStepInfo.getParent().getType()).getName()); dataFetchingType.append('.'); } dataFetchingType.append(executionStepInfo.getPath().getSegmentName()); return Tag.of("path", dataFetchingType.toString()); } + } diff --git a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/GraphQlTagsContributor.java b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/GraphQlTagsContributor.java index 6cf29d2b..eb22a52e 100644 --- a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/GraphQlTagsContributor.java +++ b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/GraphQlTagsContributor.java @@ -23,11 +23,23 @@ import graphql.execution.instrumentation.parameters.InstrumentationFieldFetchPar import graphql.schema.DataFetcher; import io.micrometer.core.instrument.Tag; +import org.springframework.lang.Nullable; + +/** + * A contributor of {@link Tag Tags} for Spring GraphQL-based request handling. Typically + * used by a {@link GraphQlTagsProvider} to provide tags in addition to its defaults. + * + * @author Brian Clozel + * @since 1.0.0 + */ public interface GraphQlTagsContributor { - Iterable getExecutionTags(InstrumentationExecutionParameters parameters, ExecutionResult result, Throwable exception); + Iterable getExecutionTags(InstrumentationExecutionParameters parameters, ExecutionResult result, + @Nullable Throwable exception); Iterable getErrorTags(InstrumentationExecutionParameters parameters, GraphQLError error); - Iterable getDataFetchingTags(DataFetcher dataFetcher, InstrumentationFieldFetchParameters parameters, Throwable exception); + Iterable getDataFetchingTags(DataFetcher dataFetcher, InstrumentationFieldFetchParameters parameters, + @Nullable Throwable exception); + } diff --git a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/GraphQlTagsProvider.java b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/GraphQlTagsProvider.java index 01ca371f..77f33011 100644 --- a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/GraphQlTagsProvider.java +++ b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/GraphQlTagsProvider.java @@ -23,12 +23,22 @@ import graphql.execution.instrumentation.parameters.InstrumentationFieldFetchPar import graphql.schema.DataFetcher; import io.micrometer.core.instrument.Tag; +import org.springframework.lang.Nullable; + +/** + * Provides {@link Tag Tags} for Spring GraphQL-based request handling. + * + * @author Brian Clozel + * @since 1.0.0 + */ public interface GraphQlTagsProvider { - Iterable getExecutionTags(InstrumentationExecutionParameters parameters, ExecutionResult result, Throwable exception); + Iterable getExecutionTags(InstrumentationExecutionParameters parameters, ExecutionResult result, + @Nullable Throwable exception); Iterable getErrorTags(InstrumentationExecutionParameters parameters, GraphQLError error); - Iterable getDataFetchingTags(DataFetcher dataFetcher, InstrumentationFieldFetchParameters parameters, Throwable exception); - + Iterable getDataFetchingTags(DataFetcher dataFetcher, InstrumentationFieldFetchParameters parameters, + @Nullable Throwable exception); + } diff --git a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/package-info.java b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/package-info.java index c4927f6d..2bab9d3d 100644 --- a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/package-info.java +++ b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/actuate/metrics/package-info.java @@ -1,3 +1,19 @@ +/* + * Copyright 2020-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. + */ + /** * Provides instrumentation support. */ diff --git a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/package-info.java b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/package-info.java index 0a71cc38..3eb17537 100644 --- a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/package-info.java +++ b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/package-info.java @@ -1,8 +1,23 @@ +/* + * Copyright 2020-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. + */ + /** * Auto-configuration classes to configure * {@link org.springframework.graphql.execution.GraphQlSource}, - * {@link org.springframework.graphql.GraphQlService}, and HTTP and WebSocket - * endpoints. + * {@link org.springframework.graphql.GraphQlService}, and HTTP and WebSocket endpoints. */ @NonNullApi @NonNullFields diff --git a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/test/tester/AutoConfigureGraphQlTester.java b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/test/tester/AutoConfigureGraphQlTester.java index ede9f3c0..34e23ebe 100644 --- a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/test/tester/AutoConfigureGraphQlTester.java +++ b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/test/tester/AutoConfigureGraphQlTester.java @@ -31,8 +31,9 @@ import org.springframework.graphql.test.tester.GraphQlTester; * * @author Brian Clozel * @see GraphQlTesterAutoConfiguration + * @since 1.0.0 */ -@Target({ElementType.TYPE, ElementType.METHOD}) +@Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited diff --git a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/test/tester/GraphQlTesterAutoConfiguration.java b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/test/tester/GraphQlTesterAutoConfiguration.java index d13786d4..b5671d72 100644 --- a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/test/tester/GraphQlTesterAutoConfiguration.java +++ b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/test/tester/GraphQlTesterAutoConfiguration.java @@ -30,18 +30,19 @@ import org.springframework.web.reactive.function.client.WebClient; /** * Auto-configuration for {@link GraphQlTester} in mock environments. - * + * * @author Brian Clozel + * @since 1.0.0 */ @Configuration(proxyBeanMethods = false) -@ConditionalOnClass({WebClient.class, WebTestClient.class, GraphQlTester.class}) +@ConditionalOnClass({ WebClient.class, WebTestClient.class, GraphQlTester.class }) @AutoConfigureAfter(value = WebTestClientMockMvcAutoConfiguration.class, name = "org.springframework.boot.test.autoconfigure.web.reactive.WebTestClientAutoConfiguration") public class GraphQlTesterAutoConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnBean(WebTestClient.class) - static class WebTestClientGraphQlTesterConfiguration { + public static class WebTestClientGraphQlTesterConfiguration { @Bean public GraphQlTester clientGraphQlTester(WebTestClient webTestClient, GraphQlProperties properties) { @@ -54,7 +55,7 @@ public class GraphQlTesterAutoConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnMissingBean(WebTestClient.class) @ConditionalOnBean(WebGraphQlHandler.class) - static class WebGraphQlHandlerGraphQlTesterConfiguration { + public static class WebGraphQlHandlerGraphQlTesterConfiguration { @Bean public GraphQlTester handlerGraphQlTester(WebGraphQlHandler handler) { diff --git a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/test/tester/GraphQlTesterContextCustomizer.java b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/test/tester/GraphQlTesterContextCustomizer.java index 04929088..57145276 100644 --- a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/test/tester/GraphQlTesterContextCustomizer.java +++ b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/test/tester/GraphQlTesterContextCustomizer.java @@ -42,7 +42,7 @@ import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.util.StringUtils; /** - * {@link ContextCustomizer} for {@link GraphQlTester} + * {@link ContextCustomizer} for {@link GraphQlTester}. * * @author Brian Clozel */ @@ -65,12 +65,13 @@ class GraphQlTesterContextCustomizer implements ContextCustomizer { } private void registerGraphQlTester(BeanDefinitionRegistry registry) { - RootBeanDefinition definition = new RootBeanDefinition(GraphQlTesterContextCustomizer.GraphQlTesterRegistrar.class); + RootBeanDefinition definition = new RootBeanDefinition( + GraphQlTesterContextCustomizer.GraphQlTesterRegistrar.class); definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - registry.registerBeanDefinition(GraphQlTesterContextCustomizer.GraphQlTesterRegistrar.class.getName(), definition); + registry.registerBeanDefinition(GraphQlTesterContextCustomizer.GraphQlTesterRegistrar.class.getName(), + definition); } - @Override public boolean equals(Object obj) { return (obj != null) && (obj.getClass() == getClass()); @@ -81,8 +82,8 @@ class GraphQlTesterContextCustomizer implements ContextCustomizer { return getClass().hashCode(); } - - private static class GraphQlTesterRegistrar implements BeanDefinitionRegistryPostProcessor, Ordered, BeanFactoryAware { + private static class GraphQlTesterRegistrar + implements BeanDefinitionRegistryPostProcessor, Ordered, BeanFactoryAware { private BeanFactory beanFactory; @@ -107,8 +108,9 @@ class GraphQlTesterContextCustomizer implements ContextCustomizer { @Override public int getOrder() { - return Ordered.LOWEST_PRECEDENCE -1; + return Ordered.LOWEST_PRECEDENCE - 1; } + } public static class GraphQlTesterFactory implements FactoryBean, ApplicationContextAware { @@ -170,4 +172,5 @@ class GraphQlTesterContextCustomizer implements ContextCustomizer { } } + } diff --git a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/test/tester/GraphQlTesterContextCustomizerFactory.java b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/test/tester/GraphQlTesterContextCustomizerFactory.java index 2bde54fe..b04e8bf2 100644 --- a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/test/tester/GraphQlTesterContextCustomizerFactory.java +++ b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/test/tester/GraphQlTesterContextCustomizerFactory.java @@ -40,7 +40,8 @@ class GraphQlTesterContextCustomizerFactory implements ContextCustomizerFactory @Override public ContextCustomizer createContextCustomizer(Class testClass, List configAttributes) { - SpringBootTest springBootTest = TestContextAnnotationUtils.findMergedAnnotation(testClass, SpringBootTest.class); + SpringBootTest springBootTest = TestContextAnnotationUtils.findMergedAnnotation(testClass, + SpringBootTest.class); return (springBootTest != null && isGraphQlTesterPresent()) ? new GraphQlTesterContextCustomizer() : null; } @@ -48,4 +49,5 @@ class GraphQlTesterContextCustomizerFactory implements ContextCustomizerFactory return ClassUtils.isPresent(WEBTESTCLIENT_CLASS, getClass().getClassLoader()) && ClassUtils.isPresent(GRAPHQLTESTER_CLASS, getClass().getClassLoader()); } + } diff --git a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/test/tester/WebTestClientMockMvcAutoConfiguration.java b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/test/tester/WebTestClientMockMvcAutoConfiguration.java index 5027ad41..e766c903 100644 --- a/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/test/tester/WebTestClientMockMvcAutoConfiguration.java +++ b/graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/test/tester/WebTestClientMockMvcAutoConfiguration.java @@ -32,13 +32,16 @@ import org.springframework.web.reactive.function.client.WebClient; /** * Auto-configuration for {@link WebTestClient} support with {@link MockMvc}. - *

Temporary workaround for upcoming enhancement request in Spring Boot 2.6.0. + *

+ * Temporary workaround for upcoming enhancement request in Spring Boot 2.6.0. * * @author Brian Clozel - * @see Spring Boot 2.6.x issue + * @since 1.0.0 + * @see Spring Boot + * 2.6.x issue */ @Configuration(proxyBeanMethods = false) -@ConditionalOnClass({ WebClient.class, WebTestClient.class, MockMvcWebTestClient.class}) +@ConditionalOnClass({ WebClient.class, WebTestClient.class, MockMvcWebTestClient.class }) @AutoConfigureAfter(name = "org.springframework.boot.test.autoconfigure.web.reactive.WebTestClientAutoConfiguration") public class WebTestClientMockMvcAutoConfiguration { @@ -52,5 +55,5 @@ public class WebTestClientMockMvcAutoConfiguration { } return builder.build(); } - + } diff --git a/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/Book.java b/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/Book.java index 871fba7a..6e192c29 100644 --- a/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/Book.java +++ b/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/Book.java @@ -1,3 +1,19 @@ +/* + * Copyright 2020-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.boot; public class Book { @@ -21,7 +37,7 @@ public class Book { } public String getId() { - return id; + return this.id; } public void setId(String id) { @@ -29,7 +45,7 @@ public class Book { } public String getName() { - return name; + return this.name; } public void setName(String name) { @@ -37,7 +53,7 @@ public class Book { } public int getPageCount() { - return pageCount; + return this.pageCount; } public void setPageCount(int pageCount) { @@ -45,10 +61,11 @@ public class Book { } public String getAuthor() { - return author; + return this.author; } public void setAuthor(String author) { this.author = author; } + } diff --git a/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/GraphQlAutoConfigurationTests.java b/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/GraphQlAutoConfigurationTests.java index 4f2087e4..174e4de4 100644 --- a/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/GraphQlAutoConfigurationTests.java +++ b/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/GraphQlAutoConfigurationTests.java @@ -35,10 +35,9 @@ class GraphQlAutoConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(GraphQlAutoConfiguration.class)); - @Test void shouldFailWhenSchemaFileIsMissing() { - contextRunner.run((context) -> { + this.contextRunner.run((context) -> { assertThat(context).hasFailed(); assertThat(context).getFailure().getRootCause().hasMessage("'schemaResource' does not exist"); }); @@ -46,29 +45,27 @@ class GraphQlAutoConfigurationTests { @Test void shouldCreateBuilderWithSdl() { - contextRunner - .withPropertyValues("spring.graphql.schema.location:classpath:books/schema.graphqls") + this.contextRunner.withPropertyValues("spring.graphql.schema.location:classpath:books/schema.graphqls") .run((context) -> assertThat(context).hasSingleBean(GraphQlSource.class)); } @Test void shouldUseProgrammaticallyDefinedBuilder() { - contextRunner - .withPropertyValues("spring.graphql.schema.location:classpath:books/schema.graphqls") - .withUserConfiguration(CustomGraphQlBuilderConfiguration.class) - .run((context) -> { + this.contextRunner.withPropertyValues("spring.graphql.schema.location:classpath:books/schema.graphqls") + .withUserConfiguration(CustomGraphQlBuilderConfiguration.class).run((context) -> { assertThat(context).hasBean("customGraphQlSourceBuilder"); assertThat(context).hasSingleBean(GraphQlSource.Builder.class); }); } - @Configuration + @Configuration(proxyBeanMethods = false) static class CustomGraphQlBuilderConfiguration { @Bean - public GraphQlSource.Builder customGraphQlSourceBuilder() { + GraphQlSource.Builder customGraphQlSourceBuilder() { return GraphQlSource.builder().schemaResource(new ClassPathResource("books/schema.graphqls")); } + } } diff --git a/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/GraphQlDataFetchers.java b/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/GraphQlDataFetchers.java index 69db2da3..8adad0ec 100644 --- a/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/GraphQlDataFetchers.java +++ b/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/GraphQlDataFetchers.java @@ -1,3 +1,19 @@ +/* + * Copyright 2020-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.boot; import java.util.Arrays; @@ -6,25 +22,24 @@ import java.util.List; import graphql.schema.DataFetcher; import reactor.core.publisher.Flux; -public class GraphQlDataFetchers { +public final class GraphQlDataFetchers { - private static List books = Arrays.asList( - new Book("book-1", "GraphQL for beginners", 100, "John GraphQL"), + private static List books = Arrays.asList(new Book("book-1", "GraphQL for beginners", 100, "John GraphQL"), new Book("book-2", "Harry Potter and the Philosopher's Stone", 223, "Joanne Rowling"), - new Book("book-3", "Moby Dick", 635, "Moby Dick"), - new Book("book-3", "Moby Dick", 635, "Moby Dick")); + new Book("book-3", "Moby Dick", 635, "Moby Dick"), new Book("book-3", "Moby Dick", 635, "Moby Dick")); + private GraphQlDataFetchers() { + + } public static DataFetcher getBookByIdDataFetcher() { - return environment -> books.stream() - .filter(book -> book.getId().equals(environment.getArgument("id"))) - .findFirst() - .orElse(null); + return (environment) -> books.stream().filter((book) -> book.getId().equals(environment.getArgument("id"))) + .findFirst().orElse(null); } public static DataFetcher getBooksOnSale() { - return environment -> Flux.fromIterable(books) - .filter(book -> book.getPageCount() >= (int) environment.getArgument("minPages")); + return (environment) -> Flux.fromIterable(books) + .filter((book) -> book.getPageCount() >= (int) environment.getArgument("minPages")); } } diff --git a/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/WebFluxApplicationContextTests.java b/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/WebFluxApplicationContextTests.java index 4109b4b4..1ba6d106 100644 --- a/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/WebFluxApplicationContextTests.java +++ b/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/WebFluxApplicationContextTests.java @@ -13,11 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.graphql.boot; import java.util.Collections; import java.util.function.Consumer; +import graphql.schema.idl.TypeRuntimeWiring; import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; @@ -35,124 +37,94 @@ import org.springframework.graphql.web.WebInterceptor; import org.springframework.http.MediaType; import org.springframework.test.web.reactive.server.WebTestClient; -import static graphql.schema.idl.TypeRuntimeWiring.newTypeWiring; - class WebFluxApplicationContextTests { private static final AutoConfigurations AUTO_CONFIGURATIONS = AutoConfigurations.of( - HttpHandlerAutoConfiguration.class, WebFluxAutoConfiguration.class, - CodecsAutoConfiguration.class, JacksonAutoConfiguration.class, - GraphQlAutoConfiguration.class, GraphQlServiceAutoConfiguration.class, + HttpHandlerAutoConfiguration.class, WebFluxAutoConfiguration.class, CodecsAutoConfiguration.class, + JacksonAutoConfiguration.class, GraphQlAutoConfiguration.class, GraphQlServiceAutoConfiguration.class, WebFluxGraphQlAutoConfiguration.class); private static final String BASE_URL = "https://spring.example.org/graphql"; - @Test void query() { - testWithWebClient(client -> { - String query = "{" + - " bookById(id: \\\"book-1\\\"){ " + - " id" + - " name" + - " pageCount" + - " author" + - " }" + - "}"; + testWithWebClient((client) -> { + String query = "{" + " bookById(id: \\\"book-1\\\"){ " + " id" + " name" + " pageCount" + + " author" + " }" + "}"; - client.post().uri("") - .bodyValue("{ \"query\": \"" + query + "\"}") - .exchange() - .expectStatus().isOk() + client.post().uri("").bodyValue("{ \"query\": \"" + query + "\"}").exchange().expectStatus().isOk() .expectBody().jsonPath("data.bookById.name").isEqualTo("GraphQL for beginners"); }); } @Test void queryMissing() { - testWithWebClient(client -> client.post().uri("").bodyValue("{}").exchange().expectStatus().isBadRequest()); + testWithWebClient((client) -> client.post().uri("").bodyValue("{}").exchange().expectStatus().isBadRequest()); } @Test void queryIsInvalidJson() { - testWithWebClient(client -> client.post().uri("").bodyValue(":)").exchange().expectStatus().isBadRequest()); + testWithWebClient((client) -> client.post().uri("").bodyValue(":)").exchange().expectStatus().isBadRequest()); } @Test void interceptedQuery() { - testWithWebClient(client -> { - String query = "{" + - " bookById(id: \\\"book-1\\\"){ " + - " id" + - " name" + - " pageCount" + - " author" + - " }" + - "}"; + testWithWebClient((client) -> { + String query = "{" + " bookById(id: \\\"book-1\\\"){ " + " id" + " name" + " pageCount" + + " author" + " }" + "}"; - client.post().uri("") - .bodyValue("{ \"query\": \"" + query + "\"}") - .exchange() - .expectStatus().isOk() + client.post().uri("").bodyValue("{ \"query\": \"" + query + "\"}").exchange().expectStatus().isOk() .expectHeader().valueEquals("X-Custom-Header", "42"); }); } @Test void schemaEndpoint() { - testWithWebClient(client -> { - client.get().uri("/schema").accept(MediaType.ALL).exchange() - .expectStatus().isOk() - .expectHeader().contentType(MediaType.TEXT_PLAIN) - .expectBody(String.class).value(Matchers.containsString("type Book")); - }); + testWithWebClient((client) -> client.get().uri("/schema").accept(MediaType.ALL).exchange().expectStatus().isOk() + .expectHeader().contentType(MediaType.TEXT_PLAIN).expectBody(String.class) + .value(Matchers.containsString("type Book"))); } private void testWithWebClient(Consumer consumer) { - testWithApplicationContext(context -> { - WebTestClient client = WebTestClient.bindToApplicationContext(context) - .configureClient() - .defaultHeaders(headers -> { + testWithApplicationContext((context) -> { + WebTestClient client = WebTestClient.bindToApplicationContext(context).configureClient() + .defaultHeaders((headers) -> { headers.setContentType(MediaType.APPLICATION_JSON); headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); - }) - .baseUrl(BASE_URL) - .build(); + }).baseUrl(BASE_URL).build(); consumer.accept(client); }); } private void testWithApplicationContext(ContextConsumer consumer) { - new ReactiveWebApplicationContextRunner() - .withConfiguration(AUTO_CONFIGURATIONS) + new ReactiveWebApplicationContextRunner().withConfiguration(AUTO_CONFIGURATIONS) .withUserConfiguration(DataFetchersConfiguration.class, CustomWebInterceptor.class) - .withPropertyValues( - "spring.main.web-application-type=reactive", + .withPropertyValues("spring.main.web-application-type=reactive", "spring.graphql.schema.printer.enabled=true", "spring.graphql.schema.location=classpath:books/schema.graphqls") .run(consumer); } - @Configuration(proxyBeanMethods = false) - static class DataFetchersConfiguration { + public static class DataFetchersConfiguration { @Bean public RuntimeWiringCustomizer bookDataFetcher() { - return (runtimeWiring) -> - runtimeWiring.type(newTypeWiring("Query") - .dataFetcher("bookById", GraphQlDataFetchers.getBookByIdDataFetcher())); + return (runtimeWiring) -> runtimeWiring.type(TypeRuntimeWiring.newTypeWiring("Query") + .dataFetcher("bookById", GraphQlDataFetchers.getBookByIdDataFetcher())); } + } @Configuration(proxyBeanMethods = false) - static class CustomWebInterceptor { + public static class CustomWebInterceptor { @Bean public WebInterceptor customWebInterceptor() { - return (input, next) -> next.handle(input).map(output -> - output.transform(builder -> builder.responseHeader("X-Custom-Header", "42"))); + return (input, next) -> next.handle(input) + .map((output) -> output.transform((builder) -> builder.responseHeader("X-Custom-Header", "42"))); } + } } diff --git a/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/WebMvcApplicationContextTests.java b/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/WebMvcApplicationContextTests.java index f772ccfb..aae02ff9 100644 --- a/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/WebMvcApplicationContextTests.java +++ b/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/WebMvcApplicationContextTests.java @@ -16,7 +16,7 @@ package org.springframework.graphql.boot; - +import graphql.schema.idl.TypeRuntimeWiring; import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; @@ -35,7 +35,6 @@ import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import static graphql.schema.idl.TypeRuntimeWiring.newTypeWiring; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; @@ -54,18 +53,12 @@ class WebMvcApplicationContextTests { @Test void endpointHandlesGraphQlQuery() { - testWith(mockMvc -> { - String query = "{" + - " bookById(id: \\\"book-1\\\"){ " + - " id" + - " name" + - " pageCount" + - " author" + - " }" + - "}"; - MvcResult asyncResult = mockMvc.perform(post("/graphql").content("{\"query\": \"" + query + "\"}")).andReturn(); - mockMvc.perform(asyncDispatch(asyncResult)) - .andExpect(status().isOk()) + testWith((mockMvc) -> { + String query = "{" + " bookById(id: \\\"book-1\\\"){ " + " id" + " name" + " pageCount" + + " author" + " }" + "}"; + MvcResult asyncResult = mockMvc.perform(post("/graphql").content("{\"query\": \"" + query + "\"}")) + .andReturn(); + mockMvc.perform(asyncDispatch(asyncResult)).andExpect(status().isOk()) .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("data.bookById.name").value("GraphQL for beginners")); }); @@ -73,83 +66,73 @@ class WebMvcApplicationContextTests { @Test void missingQuery() { - testWith(mockMvc -> mockMvc.perform(post("/graphql").content("{}")).andExpect(status().isBadRequest())); + testWith((mockMvc) -> mockMvc.perform(post("/graphql").content("{}")).andExpect(status().isBadRequest())); } @Test void invalidJson() { - testWith(mockMvc -> mockMvc.perform(post("/graphql").content(":)")).andExpect(status().isBadRequest())); + testWith((mockMvc) -> mockMvc.perform(post("/graphql").content(":)")).andExpect(status().isBadRequest())); } @Test void interceptedQuery() { - testWith(mockMvc -> { - String query = "{" + - " bookById(id: \\\"book-1\\\"){ " + - " id" + - " name" + - " pageCount" + - " author" + - " }" + - "}"; - MvcResult asyncResult = mockMvc.perform(post("/graphql").content("{\"query\": \"" + query + "\"}")).andReturn(); - mockMvc.perform(asyncDispatch(asyncResult)) - .andExpect(status().isOk()) + testWith((mockMvc) -> { + String query = "{" + " bookById(id: \\\"book-1\\\"){ " + " id" + " name" + " pageCount" + + " author" + " }" + "}"; + MvcResult asyncResult = mockMvc.perform(post("/graphql").content("{\"query\": \"" + query + "\"}")) + .andReturn(); + mockMvc.perform(asyncDispatch(asyncResult)).andExpect(status().isOk()) .andExpect(header().string("X-Custom-Header", "42")); }); } @Test void schemaEndpoint() { - testWith(mockMvc -> { - mockMvc.perform(get("/graphql/schema")).andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.TEXT_PLAIN)) - .andExpect(content().string(Matchers.containsString("type Book"))); - }); + testWith((mockMvc) -> mockMvc.perform(get("/graphql/schema")).andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.TEXT_PLAIN)) + .andExpect(content().string(Matchers.containsString("type Book")))); } private void testWith(MockMvcConsumer mockMvcConsumer) { - new WebApplicationContextRunner() - .withConfiguration(AUTO_CONFIGURATIONS) + new WebApplicationContextRunner().withConfiguration(AUTO_CONFIGURATIONS) .withUserConfiguration(DataFetchersConfiguration.class, CustomWebInterceptor.class) - .withPropertyValues( - "spring.main.web-application-type=servlet", + .withPropertyValues("spring.main.web-application-type=servlet", "spring.graphql.schema.printer.enabled=true", "spring.graphql.schema.location=classpath:books/schema.graphqls") .run((context) -> { - MockHttpServletRequestBuilder builder = post("/graphql") - .contentType(MediaType.APPLICATION_JSON) + MockHttpServletRequestBuilder builder = post("/graphql").contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON); MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context).defaultRequest(builder).build(); mockMvcConsumer.accept(mockMvc); }); } - - private static interface MockMvcConsumer { + private interface MockMvcConsumer { void accept(MockMvc mockMvc) throws Exception; } @Configuration(proxyBeanMethods = false) - static class DataFetchersConfiguration { + public static class DataFetchersConfiguration { @Bean public RuntimeWiringCustomizer bookDataFetcher() { - return (builder) -> builder.type(newTypeWiring("Query") - .dataFetcher("bookById", GraphQlDataFetchers.getBookByIdDataFetcher())); + return (builder) -> builder.type(TypeRuntimeWiring.newTypeWiring("Query").dataFetcher("bookById", + GraphQlDataFetchers.getBookByIdDataFetcher())); } + } @Configuration(proxyBeanMethods = false) - static class CustomWebInterceptor { + public static class CustomWebInterceptor { @Bean public WebInterceptor customWebInterceptor() { - return (input, next) -> next.handle(input).map(output -> - output.transform(builder -> builder.responseHeader("X-Custom-Header", "42"))); + return (input, next) -> next.handle(input) + .map((output) -> output.transform((builder) -> builder.responseHeader("X-Custom-Header", "42"))); } + } } diff --git a/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/actuate/metrics/GraphQlTagsTests.java b/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/actuate/metrics/GraphQlTagsTests.java index 39f034f6..e7ae182c 100644 --- a/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/actuate/metrics/GraphQlTagsTests.java +++ b/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/actuate/metrics/GraphQlTagsTests.java @@ -31,7 +31,7 @@ import static org.assertj.core.api.Assertions.assertThat; /** * Tests for {@link GraphQlTags} - * + * * @author Brian Clozel */ class GraphQlTagsTests { @@ -44,7 +44,8 @@ class GraphQlTagsTests { @Test void executionOutcomeShouldErrorWhenExceptionThrown() { - Tag outcomeTag = GraphQlTags.executionOutcome(new TestExecutionResult(), new IllegalArgumentException("test error")); + Tag outcomeTag = GraphQlTags.executionOutcome(new TestExecutionResult(), + new IllegalArgumentException("test error")); assertThat(outcomeTag.getValue()).isEqualTo("ERROR"); } @@ -58,21 +59,24 @@ class GraphQlTagsTests { @Test void errorTypeShouldBeDefinedIfPresent() { - GraphQLError error = GraphqlErrorBuilder.newError().errorType(ErrorType.DataFetchingException).message("test error").build(); + GraphQLError error = GraphqlErrorBuilder.newError().errorType(ErrorType.DataFetchingException) + .message("test error").build(); Tag errorTypeTag = GraphQlTags.errorType(error); assertThat(errorTypeTag.getValue()).isEqualTo("DataFetchingException"); } @Test void errorPathShouldUseJsonPathFormat() { - GraphQLError error = GraphqlErrorBuilder.newError().path(Arrays.asList("project", "name")).message("test error").build(); + GraphQLError error = GraphqlErrorBuilder.newError().path(Arrays.asList("project", "name")).message("test error") + .build(); Tag errorPathTag = GraphQlTags.errorPath(error); assertThat(errorPathTag.getValue()).isEqualTo("$.project.name"); } @Test void errorPathShouldUseJsonPathFormatForIndices() { - GraphQLError error = GraphqlErrorBuilder.newError().path(Arrays.asList("issues", "42", "title")).message("test error").build(); + GraphQLError error = GraphqlErrorBuilder.newError().path(Arrays.asList("issues", "42", "title")) + .message("test error").build(); Tag errorPathTag = GraphQlTags.errorPath(error); assertThat(errorPathTag.getValue()).isEqualTo("$.issues[*].title"); } @@ -89,4 +93,4 @@ class GraphQlTagsTests { assertThat(fetchingOutcomeTag.getValue()).isEqualTo("ERROR"); } -} \ No newline at end of file +} diff --git a/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/test/tester/GraphQlTesterAutoConfigurationTests.java b/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/test/tester/GraphQlTesterAutoConfigurationTests.java index e21bd584..a4868548 100644 --- a/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/test/tester/GraphQlTesterAutoConfigurationTests.java +++ b/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/test/tester/GraphQlTesterAutoConfigurationTests.java @@ -75,7 +75,6 @@ class GraphQlTesterAutoConfigurationTests { return mock(WebGraphQlHandler.class); } - } @Configuration(proxyBeanMethods = false) @@ -84,7 +83,7 @@ class GraphQlTesterAutoConfigurationTests { @Bean WebTestClient webTestClient() { RouterFunction routerFunction = RouterFunctions.route() - .POST("/graphql", request -> ServerResponse.ok().build()).build(); + .POST("/graphql", (request) -> ServerResponse.ok().build()).build(); return WebTestClient.bindToRouterFunction(routerFunction).build(); } @@ -94,4 +93,5 @@ class GraphQlTesterAutoConfigurationTests { } } + } diff --git a/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/test/tester/GraphQlTesterContextCustomizerIntegrationTests.java b/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/test/tester/GraphQlTesterContextCustomizerIntegrationTests.java index b2df7a37..6a1760d2 100644 --- a/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/test/tester/GraphQlTesterContextCustomizerIntegrationTests.java +++ b/graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/test/tester/GraphQlTesterContextCustomizerIntegrationTests.java @@ -43,11 +43,13 @@ import org.springframework.test.annotation.DirtiesContext; * * @author Brian Clozel */ -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = "spring.main.web-application-type=reactive") +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + properties = "spring.main.web-application-type=reactive") @DirtiesContext class GraphQlTesterContextCustomizerIntegrationTests { - @Autowired GraphQlTester graphQlTester; + @Autowired + GraphQlTester graphQlTester; @Test void test() { @@ -69,6 +71,7 @@ class GraphQlTesterContextCustomizerIntegrationTests { Map handlersMap = Collections.singletonMap(properties.getPath(), httpHandler); return new ContextPathCompositeHandler(handlersMap); } + } static class TestHandler implements HttpHandler { @@ -83,4 +86,5 @@ class GraphQlTesterContextCustomizerIntegrationTests { } } -} \ No newline at end of file + +}