You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2022/04/22 07:50:50 UTC

[isis] branch master updated: Bump spring-graphql 1.0.0-M4 -> 1.0.0-RC1

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/master by this push:
     new df9f5e8530 Bump spring-graphql 1.0.0-M4 -> 1.0.0-RC1
df9f5e8530 is described below

commit df9f5e8530e063dcbe0c306a1999e4b3fe487e95
Author: Andi Huber <ah...@apache.org>
AuthorDate: Fri Apr 22 09:50:43 2022 +0200

    Bump spring-graphql 1.0.0-M4 -> 1.0.0-RC1
---
 core/pom.xml                                       |   6 +
 extensions/core/command-log/applib/pom.xml         |  24 ++-
 extensions/core/command-log/jdo/pom.xml            |  24 ++-
 extensions/core/command-log/jpa/pom.xml            |  26 +--
 extensions/core/command-log/pom.xml                |  12 --
 incubator/viewers/graphql/pom.xml                  |   4 +-
 incubator/viewers/graphql/viewer/pom.xml           | 101 ++-------
 .../viewer/source/GraphQlServiceForIsis.java       |  18 +-
 .../viewer/spring/GraphQlAutoConfiguration.java    | 157 +++++++-------
 .../spring/GraphQlWebMvcAutoConfiguration.java     | 236 +++++++++++----------
 10 files changed, 286 insertions(+), 322 deletions(-)

diff --git a/core/pom.xml b/core/pom.xml
index 4f6853c648..81f280d0dc 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -675,6 +675,12 @@
 				<version>2.0.0-SNAPSHOT</version>
 				<type>pom</type>
 			</dependency>
+			<dependency>
+				<groupId>org.apache.isis.testing</groupId>
+				<artifactId>isis-testing</artifactId>
+				<version>2.0.0-SNAPSHOT</version>
+				<type>pom</type>
+			</dependency>
 
 			<!-- THIRD PARTY DEPENDENCIES -->
 
diff --git a/extensions/core/command-log/applib/pom.xml b/extensions/core/command-log/applib/pom.xml
index 86be82e515..51b7437517 100644
--- a/extensions/core/command-log/applib/pom.xml
+++ b/extensions/core/command-log/applib/pom.xml
@@ -71,19 +71,21 @@
 		    <artifactId>javax.jdo</artifactId>
 		</dependency>
 
-        <!-- Testing -->
-
-        <dependency>
-	    	<groupId>org.apache.isis.testing</groupId>
-        	<artifactId>isis-testing-unittestsupport-applib</artifactId>
+        <!-- TESTING -->
+		
+		<dependency>
+			<groupId>org.apache.isis.mavendeps</groupId>
+			<artifactId>isis-mavendeps-unittests</artifactId>
+			<type>pom</type>
             <scope>test</scope>
-        </dependency>
-
-        <dependency>
-	    	<groupId>org.apache.isis.testing</groupId>
-        	<artifactId>isis-testing-integtestsupport-applib</artifactId>
+		</dependency>
+		
+		<dependency>
+			<groupId>org.apache.isis.mavendeps</groupId>
+			<artifactId>isis-mavendeps-integtests</artifactId>
+			<type>pom</type>
             <scope>test</scope>
-        </dependency>
+		</dependency>
 
     </dependencies>
 
diff --git a/extensions/core/command-log/jdo/pom.xml b/extensions/core/command-log/jdo/pom.xml
index 430b875cc7..5649ec4471 100644
--- a/extensions/core/command-log/jdo/pom.xml
+++ b/extensions/core/command-log/jdo/pom.xml
@@ -58,19 +58,21 @@
 			<artifactId>isis-persistence-jdo-datanucleus</artifactId>
         </dependency>
 
-        <!-- Testing -->
-
-        <dependency>
-	    	<groupId>org.apache.isis.testing</groupId>
-        	<artifactId>isis-testing-unittestsupport-applib</artifactId>
+        <!-- TESTING -->
+		
+		<dependency>
+			<groupId>org.apache.isis.mavendeps</groupId>
+			<artifactId>isis-mavendeps-unittests</artifactId>
+			<type>pom</type>
             <scope>test</scope>
-        </dependency>
-
-        <dependency>
-	    	<groupId>org.apache.isis.testing</groupId>
-        	<artifactId>isis-testing-integtestsupport-applib</artifactId>
+		</dependency>
+		
+		<dependency>
+			<groupId>org.apache.isis.mavendeps</groupId>
+			<artifactId>isis-mavendeps-integtests</artifactId>
+			<type>pom</type>
             <scope>test</scope>
-        </dependency>
+		</dependency>
 
     </dependencies>
 
diff --git a/extensions/core/command-log/jpa/pom.xml b/extensions/core/command-log/jpa/pom.xml
index a06f71e273..6c50de6606 100644
--- a/extensions/core/command-log/jpa/pom.xml
+++ b/extensions/core/command-log/jpa/pom.xml
@@ -57,20 +57,22 @@
 			<groupId>org.apache.isis.persistence</groupId>
 			<artifactId>isis-persistence-jpa-eclipselink</artifactId>
 		</dependency>
-
-        <!-- Testing -->
-
-        <dependency>
-	    	<groupId>org.apache.isis.testing</groupId>
-        	<artifactId>isis-testing-unittestsupport-applib</artifactId>
+		
+        <!-- TESTING -->
+		
+		<dependency>
+			<groupId>org.apache.isis.mavendeps</groupId>
+			<artifactId>isis-mavendeps-unittests</artifactId>
+			<type>pom</type>
             <scope>test</scope>
-        </dependency>
-
-        <dependency>
-	    	<groupId>org.apache.isis.testing</groupId>
-        	<artifactId>isis-testing-integtestsupport-applib</artifactId>
+		</dependency>
+		
+		<dependency>
+			<groupId>org.apache.isis.mavendeps</groupId>
+			<artifactId>isis-mavendeps-integtests</artifactId>
+			<type>pom</type>
             <scope>test</scope>
-        </dependency>
+		</dependency>
 
     </dependencies>
 
diff --git a/extensions/core/command-log/pom.xml b/extensions/core/command-log/pom.xml
index b12024a044..396de63fb0 100644
--- a/extensions/core/command-log/pom.xml
+++ b/extensions/core/command-log/pom.xml
@@ -27,18 +27,6 @@
 
 	<packaging>pom</packaging>
 
-	<dependencyManagement>
-		<dependencies>
-			<dependency>
-				<groupId>org.apache.isis.testing</groupId>
-				<artifactId>isis-testing</artifactId>
-				<version>2.0.0-SNAPSHOT</version>
-				<scope>import</scope>
-				<type>pom</type>
-			</dependency>
-		</dependencies>
-	</dependencyManagement>
-
 	<modules>
 		<module>applib</module>
 		<module>jdo</module>
diff --git a/incubator/viewers/graphql/pom.xml b/incubator/viewers/graphql/pom.xml
index 74ad74e736..2053282575 100644
--- a/incubator/viewers/graphql/pom.xml
+++ b/incubator/viewers/graphql/pom.xml
@@ -77,8 +77,8 @@
 
 			<dependency>
 				<groupId>org.springframework.graphql</groupId>
-				<artifactId>spring-graphql</artifactId>
-				<version>1.0.0-M5</version>
+  				<artifactId>spring-graphql</artifactId>
+  				<version>1.0.0-RC1</version>
 			</dependency>
 
 			<dependency>
diff --git a/incubator/viewers/graphql/viewer/pom.xml b/incubator/viewers/graphql/viewer/pom.xml
index 175ba5f755..480e100407 100644
--- a/incubator/viewers/graphql/viewer/pom.xml
+++ b/incubator/viewers/graphql/viewer/pom.xml
@@ -1,13 +1,13 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor
-	license agreements. See the NOTICE file distributed with this work for additional
-	information regarding copyright ownership. The ASF licenses this file to
-	you 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 http://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
+<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor 
+	license agreements. See the NOTICE file distributed with this work for additional 
+	information regarding copyright ownership. The ASF licenses this file to 
+	you 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 http://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. -->
 <project xmlns="http://maven.apache.org/POM/4.0.0"
 	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -52,22 +52,23 @@
 		<dependency>
 			<groupId>org.springframework.boot</groupId>
 			<artifactId>spring-boot-starter-websocket</artifactId>
+			<exclusions>
+				<exclusion>
+					<groupId>org.springframework.boot</groupId>
+					<artifactId>spring-boot-starter-logging</artifactId>
+				</exclusion>
+			</exclusions>
 		</dependency>
+
+		<!-- TESTING -->
+
 		<dependency>
-			<groupId>org.junit.jupiter</groupId>
-			<artifactId>junit-jupiter-api</artifactId>
-			<scope>test</scope>
-		</dependency>
-		<dependency>
-			<groupId>org.junit.jupiter</groupId>
-			<artifactId>junit-jupiter-engine</artifactId>
-			<scope>test</scope>
-		</dependency>
-		<dependency>
-			<groupId>org.junit.jupiter</groupId>
-			<artifactId>junit-jupiter-params</artifactId>
+			<groupId>org.apache.isis.mavendeps</groupId>
+			<artifactId>isis-mavendeps-unittests</artifactId>
+			<type>pom</type>
 			<scope>test</scope>
 		</dependency>
+
 		<dependency>
 			<groupId>org.assertj</groupId>
 			<artifactId>assertj-core</artifactId>
@@ -78,46 +79,7 @@
 			<artifactId>mockito-core</artifactId>
 			<scope>test</scope>
 		</dependency>
-<!--        <dependency>-->
-<!--            <groupId>org.springframework.boot</groupId>-->
-<!--            <artifactId>spring-boot-test</artifactId>-->
-<!--            <scope>test</scope>-->
-<!--        </dependency>-->
-		<dependency>
-			<groupId>org.springframework.boot</groupId>
-			<artifactId>spring-boot-starter-test</artifactId>
-			<exclusions>
-				<exclusion>
-					<groupId>org.ow2.asm</groupId>
-					<artifactId>asm</artifactId>
-				</exclusion>
-				<exclusion>
-					<!-- when spring-boot release lags behind spring-core release explicitly
-						spring-test added below -->
-					<groupId>org.springframework</groupId>
-					<artifactId>spring-test</artifactId>
-				</exclusion>
-				<exclusion>
-					<!-- when spring-boot release lags behind spring-core release explicitly
-						spring-test added below -->
-					<groupId>org.springframework</groupId>
-					<artifactId>spring-core</artifactId>
-				</exclusion>
-				<exclusion>
-					<!-- we use log4j-2 instead -->
-					<groupId>org.springframework.boot</groupId>
-					<artifactId>spring-boot-starter-logging</artifactId>
-				</exclusion>
-				<exclusion>
-					<groupId>org.slf4j</groupId>
-					<artifactId>slf4j-api</artifactId>
-				</exclusion>
-				<exclusion>
-					<groupId>org.junit.vintage</groupId>
-					<artifactId>junit-vintage-engine</artifactId>
-				</exclusion>
-			</exclusions>
-		</dependency>
+
 		<dependency>
 			<groupId>org.springframework</groupId>
 			<artifactId>spring-test</artifactId>
@@ -154,23 +116,6 @@
 			<scope>test</scope>
 		</dependency>
 
-<!-- 		<dependency> -->
-<!-- 			<groupId>com.google.guava</groupId> -->
-<!-- 			<artifactId>guava</artifactId> -->
-<!-- 			<scope>test</scope> -->
-<!-- 		</dependency> -->
-
-<!-- 		<dependency> -->
-<!-- 			<groupId>com.fasterxml.jackson.core</groupId> -->
-<!-- 			<artifactId>jackson-core</artifactId> -->
-<!-- 			<scope>test</scope> -->
-<!-- 		</dependency> -->
-<!-- 		<dependency> -->
-<!-- 			<groupId>com.fasterxml.jackson.core</groupId> -->
-<!-- 			<artifactId>jackson-databind</artifactId> -->
-<!-- 			<scope>test</scope> -->
-<!-- 		</dependency> -->
-
 	</dependencies>
 
 
diff --git a/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/GraphQlServiceForIsis.java b/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/GraphQlServiceForIsis.java
index 260dad74cf..a49ffb4f3d 100644
--- a/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/GraphQlServiceForIsis.java
+++ b/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/source/GraphQlServiceForIsis.java
@@ -2,11 +2,11 @@ package org.apache.isis.viewer.graphql.viewer.source;
 
 import javax.inject.Inject;
 
-import org.springframework.graphql.GraphQlService;
-import org.springframework.graphql.RequestInput;
-import org.springframework.graphql.RequestOutput;
+import org.springframework.graphql.ExecutionGraphQlRequest;
+import org.springframework.graphql.ExecutionGraphQlResponse;
+import org.springframework.graphql.ExecutionGraphQlService;
 import org.springframework.graphql.execution.BatchLoaderRegistry;
-import org.springframework.graphql.execution.ExecutionGraphQlService;
+import org.springframework.graphql.execution.DefaultExecutionGraphQlService;
 import org.springframework.graphql.execution.GraphQlSource;
 import org.springframework.stereotype.Service;
 
@@ -19,19 +19,19 @@ import reactor.core.publisher.Mono;
  */
 @Service()
 @RequiredArgsConstructor(onConstructor_ = {@Inject})
-public class GraphQlServiceForIsis implements GraphQlService {
+public class GraphQlServiceForIsis implements ExecutionGraphQlService {
 
     private final BatchLoaderRegistry batchLoaderRegistry;
     private final GraphQlSource graphQlSource;
 
-    ExecutionGraphQlService delegate;
+    DefaultExecutionGraphQlService delegate;
 
     @Override
-    public Mono<RequestOutput> execute(RequestInput input) {
+    public Mono<ExecutionGraphQlResponse> execute(final ExecutionGraphQlRequest request) {
         if(delegate == null) {
-            delegate = new ExecutionGraphQlService(graphQlSource);
+            delegate = new DefaultExecutionGraphQlService(graphQlSource);
             delegate.addDataLoaderRegistrar(batchLoaderRegistry);
         }
-        return delegate.execute(input);
+        return delegate.execute(request);
     }
 }
diff --git a/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/spring/GraphQlAutoConfiguration.java b/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/spring/GraphQlAutoConfiguration.java
index 75fd295605..a6c8b2e2b6 100644
--- a/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/spring/GraphQlAutoConfiguration.java
+++ b/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/spring/GraphQlAutoConfiguration.java
@@ -19,33 +19,35 @@ package org.apache.isis.viewer.graphql.viewer.spring;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.stream.Collectors;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.ListableBeanFactory;
 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;
+import org.springframework.boot.convert.ApplicationConversionService;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.core.io.Resource;
 import org.springframework.core.io.support.ResourcePatternResolver;
-import org.springframework.format.support.DefaultFormattingConversionService;
-import org.springframework.graphql.GraphQlService;
+import org.springframework.graphql.ExecutionGraphQlService;
 import org.springframework.graphql.data.method.annotation.support.AnnotatedControllerConfigurer;
 import org.springframework.graphql.execution.BatchLoaderRegistry;
 import org.springframework.graphql.execution.DataFetcherExceptionResolver;
 import org.springframework.graphql.execution.DefaultBatchLoaderRegistry;
-import org.springframework.graphql.execution.ExecutionGraphQlService;
+import org.springframework.graphql.execution.DefaultExecutionGraphQlService;
 import org.springframework.graphql.execution.GraphQlSource;
-import org.springframework.graphql.execution.MissingSchemaException;
 import org.springframework.graphql.execution.RuntimeWiringConfigurer;
 
 import graphql.GraphQL;
 import graphql.execution.instrumentation.Instrumentation;
+import graphql.schema.idl.RuntimeWiring.Builder;
 import graphql.schema.visibility.NoIntrospectionGraphqlFieldVisibility;
 
 /**
@@ -62,74 +64,83 @@ public class GraphQlAutoConfiguration {
 
 	private static final Log logger = LogFactory.getLog(GraphQlAutoConfiguration.class);
 
-	private final BatchLoaderRegistry batchLoaderRegistry = new DefaultBatchLoaderRegistry();
-
-	@Bean
-	 @ConditionalOnMissingBean
-	public GraphQlSource graphQlSource(ResourcePatternResolver resourcePatternResolver, GraphQlProperties properties,
-			ObjectProvider<DataFetcherExceptionResolver> exceptionResolversProvider,
-			ObjectProvider<Instrumentation> instrumentationsProvider,
-			ObjectProvider<RuntimeWiringConfigurer> wiringConfigurers,
-			ObjectProvider<GraphQlSourceBuilderCustomizer> sourceCustomizers) {
-
-		List<Resource> schemaResources = resolveSchemaResources(resourcePatternResolver,
-				properties.getSchema().getLocations(), properties.getSchema().getFileExtensions());
-		GraphQlSource.Builder builder = GraphQlSource.builder()
-				.schemaResources(schemaResources.toArray(new Resource[0]))
-				.exceptionResolvers(exceptionResolversProvider.orderedStream().collect(Collectors.toList()))
-				.instrumentation(instrumentationsProvider.orderedStream().collect(Collectors.toList()));
-		if (!properties.getSchema().getIntrospection().isEnabled()) {
-			builder.configureRuntimeWiring((wiring) -> wiring
-					.fieldVisibility(NoIntrospectionGraphqlFieldVisibility.NO_INTROSPECTION_FIELD_VISIBILITY));
-		}
-		wiringConfigurers.orderedStream().forEach(builder::configureRuntimeWiring);
-		sourceCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
-		try {
-			return builder.build();
-		}
-		catch (MissingSchemaException exc) {
-			throw new InvalidSchemaLocationsException(properties.getSchema().getLocations(), resourcePatternResolver,
-					exc);
-		}
-	}
-
-	@Bean
-	@ConditionalOnMissingBean
-	public BatchLoaderRegistry batchLoaderRegistry() {
-		return this.batchLoaderRegistry;
-	}
-
-	@Bean
-	@ConditionalOnMissingBean
-	public GraphQlService graphQlService(GraphQlSource graphQlSource) {
-		ExecutionGraphQlService service = new ExecutionGraphQlService(graphQlSource);
-		service.addDataLoaderRegistrar(this.batchLoaderRegistry);
-		return service;
-	}
-
-	@Bean
-	@ConditionalOnMissingBean
-	public AnnotatedControllerConfigurer annotatedControllerConfigurer() {
-		AnnotatedControllerConfigurer annotatedControllerConfigurer = new AnnotatedControllerConfigurer();
-		annotatedControllerConfigurer.setConversionService(new DefaultFormattingConversionService());
-		return annotatedControllerConfigurer;
-	}
-
-	private List<Resource> resolveSchemaResources(ResourcePatternResolver resolver, String[] schemaLocations,
-			String[] fileExtensions) {
-		List<Resource> schemaResources = new ArrayList<>();
-		for (String location : schemaLocations) {
-			for (String extension : fileExtensions) {
-				String resourcePattern = location + "*" + extension;
-				try {
-					schemaResources.addAll(Arrays.asList(resolver.getResources(resourcePattern)));
-				}
-				catch (IOException ex) {
-					logger.debug("Could not resolve schema location: '" + resourcePattern + "'", ex);
-				}
-			}
-		}
-		return schemaResources;
-	}
+    private final ListableBeanFactory beanFactory;
+
+    public GraphQlAutoConfiguration(final ListableBeanFactory beanFactory) {
+        this.beanFactory = beanFactory;
+    }
+
+    @Bean
+    @ConditionalOnMissingBean
+    public GraphQlSource graphQlSource(final ResourcePatternResolver resourcePatternResolver, final GraphQlProperties properties,
+            final ObjectProvider<DataFetcherExceptionResolver> exceptionResolvers,
+            final ObjectProvider<Instrumentation> instrumentations, final ObjectProvider<RuntimeWiringConfigurer> wiringConfigurers,
+            final ObjectProvider<GraphQlSourceBuilderCustomizer> sourceCustomizers) {
+        String[] schemaLocations = properties.getSchema().getLocations();
+        Resource[] schemaResources = resolveSchemaResources(resourcePatternResolver, schemaLocations,
+                properties.getSchema().getFileExtensions());
+        GraphQlSource.SchemaResourceBuilder builder = GraphQlSource.schemaResourceBuilder()
+                .schemaResources(schemaResources).exceptionResolvers(toList(exceptionResolvers))
+                .instrumentation(toList(instrumentations));
+        if (!properties.getSchema().getIntrospection().isEnabled()) {
+            builder.configureRuntimeWiring(this::enableIntrospection);
+        }
+        wiringConfigurers.orderedStream().forEach(builder::configureRuntimeWiring);
+        sourceCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
+        return builder.build();
+    }
+
+    private Builder enableIntrospection(final Builder wiring) {
+        return wiring.fieldVisibility(NoIntrospectionGraphqlFieldVisibility.NO_INTROSPECTION_FIELD_VISIBILITY);
+    }
+
+    private Resource[] resolveSchemaResources(final ResourcePatternResolver resolver, final String[] locations,
+            final String[] extensions) {
+        List<Resource> resources = new ArrayList<>();
+        for (String location : locations) {
+            for (String extension : extensions) {
+                resources.addAll(resolveSchemaResources(resolver, location + "*" + extension));
+            }
+        }
+        return resources.toArray(new Resource[0]);
+    }
+
+    private List<Resource> resolveSchemaResources(final ResourcePatternResolver resolver, final String pattern) {
+        try {
+            return Arrays.asList(resolver.getResources(pattern));
+        }
+        catch (IOException ex) {
+            logger.debug("Could not resolve schema location: '" + pattern + "'", ex);
+            return Collections.emptyList();
+        }
+    }
+
+    @Bean
+    @ConditionalOnMissingBean
+    public BatchLoaderRegistry batchLoaderRegistry() {
+        return new DefaultBatchLoaderRegistry();
+    }
+
+    @Bean
+    @ConditionalOnMissingBean
+    public ExecutionGraphQlService executionGraphQlService(final GraphQlSource graphQlSource,
+            final BatchLoaderRegistry batchLoaderRegistry) {
+        DefaultExecutionGraphQlService service = new DefaultExecutionGraphQlService(graphQlSource);
+        service.addDataLoaderRegistrar(batchLoaderRegistry);
+        return service;
+    }
+
+    @Bean
+    @ConditionalOnMissingBean
+    public AnnotatedControllerConfigurer annotatedControllerConfigurer() {
+        AnnotatedControllerConfigurer controllerConfigurer = new AnnotatedControllerConfigurer();
+        controllerConfigurer
+                .addFormatterRegistrar((registry) -> ApplicationConversionService.addBeans(registry, this.beanFactory));
+        return controllerConfigurer;
+    }
+
+    private <T> List<T> toList(final ObjectProvider<T> provider) {
+        return provider.orderedStream().collect(Collectors.toList());
+    }
 
 }
diff --git a/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/spring/GraphQlWebMvcAutoConfiguration.java b/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/spring/GraphQlWebMvcAutoConfiguration.java
index 65c49edf4e..f4db88443b 100644
--- a/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/spring/GraphQlWebMvcAutoConfiguration.java
+++ b/incubator/viewers/graphql/viewer/src/main/java/org/apache/isis/viewer/graphql/viewer/spring/GraphQlWebMvcAutoConfiguration.java
@@ -36,20 +36,22 @@ import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.core.io.ResourceLoader;
-import org.springframework.graphql.GraphQlService;
+import org.springframework.core.log.LogMessage;
+import org.springframework.graphql.ExecutionGraphQlService;
 import org.springframework.graphql.execution.GraphQlSource;
 import org.springframework.graphql.execution.ThreadLocalAccessor;
-import org.springframework.graphql.web.WebGraphQlHandler;
-import org.springframework.graphql.web.WebInterceptor;
-import org.springframework.graphql.web.webmvc.GraphQlHttpHandler;
-import org.springframework.graphql.web.webmvc.GraphQlWebSocketHandler;
-import org.springframework.graphql.web.webmvc.GraphiQlHandler;
-import org.springframework.graphql.web.webmvc.SchemaHandler;
+import org.springframework.graphql.server.WebGraphQlHandler;
+import org.springframework.graphql.server.WebGraphQlInterceptor;
+import org.springframework.graphql.server.webmvc.GraphQlHttpHandler;
+import org.springframework.graphql.server.webmvc.GraphQlWebSocketHandler;
+import org.springframework.graphql.server.webmvc.GraphiQlHandler;
+import org.springframework.graphql.server.webmvc.SchemaHandler;
+import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpMethod;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
 import org.springframework.http.converter.GenericHttpMessageConverter;
+import org.springframework.http.converter.HttpMessageConverter;
 import org.springframework.web.cors.CorsConfiguration;
 import org.springframework.web.servlet.HandlerMapping;
 import org.springframework.web.servlet.config.annotation.CorsRegistry;
@@ -57,11 +59,11 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 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.ServerRequest;
 import org.springframework.web.servlet.function.ServerResponse;
 import org.springframework.web.socket.WebSocketHandler;
 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 graphql.GraphQL;
 
@@ -77,116 +79,122 @@ import graphql.GraphQL;
 @Configuration(proxyBeanMethods = false)
 @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
 @ConditionalOnClass({ GraphQL.class, GraphQlHttpHandler.class })
-@ConditionalOnBean(GraphQlService.class)
+@ConditionalOnBean(ExecutionGraphQlService.class)
 @AutoConfigureAfter(GraphQlAutoConfiguration.class)
 @EnableConfigurationProperties(GraphQlCorsProperties.class)
 public class GraphQlWebMvcAutoConfiguration {
 
 	private static final Log logger = LogFactory.getLog(GraphQlWebMvcAutoConfiguration.class);
 
-	@Bean
-	@ConditionalOnMissingBean
-	public GraphQlHttpHandler graphQlHttpHandler(WebGraphQlHandler webGraphQlHandler) {
-		return new GraphQlHttpHandler(webGraphQlHandler);
-	}
-
-	@Bean
-	@ConditionalOnMissingBean
-	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();
-	}
-
-	@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);
-		}
-
-		RouterFunctions.Builder builder = RouterFunctions.route()
-				.GET(graphQLPath,
-						(request) -> ServerResponse.status(HttpStatus.METHOD_NOT_ALLOWED)
-								.headers((headers) -> headers.setAllow(Collections.singleton(HttpMethod.POST))).build())
-				.POST(graphQLPath, RequestPredicates.contentType(MediaType.APPLICATION_JSON)
-						.and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), handler::handleRequest);
-
-		if (properties.getGraphiql().isEnabled()) {
-			GraphiQlHandler graphiQLHandler = new GraphiQlHandler(graphQLPath, properties.getWebsocket().getPath());
-			builder = builder.GET(properties.getGraphiql().getPath(), graphiQLHandler::handleRequest);
-		}
-
-		if (properties.getSchema().getPrinter().isEnabled()) {
-			SchemaHandler schemaHandler = new SchemaHandler(graphQlSource);
-			builder = builder.GET(graphQLPath + "/schema", schemaHandler::handleRequest);
-		}
-
-		return builder.build();
-	}
-
-	@Configuration(proxyBeanMethods = false)
-	public static class GraphQlEndpointCorsConfiguration implements WebMvcConfigurer {
-
-		final GraphQlProperties graphQlProperties;
-
-		final GraphQlCorsProperties corsProperties;
-
-		public GraphQlEndpointCorsConfiguration(GraphQlProperties graphQlProps, GraphQlCorsProperties corsProps) {
-			this.graphQlProperties = graphQlProps;
-			this.corsProperties = corsProps;
-		}
-
-		@Override
-		public void addCorsMappings(CorsRegistry registry) {
-			CorsConfiguration configuration = this.corsProperties.toCorsConfiguration();
-			if (configuration != null) {
-				registry.addMapping(this.graphQlProperties.getPath()).combine(configuration);
-			}
-		}
-
-	}
-
-	@Configuration(proxyBeanMethods = false)
-	@ConditionalOnClass({ ServerContainer.class, WebSocketHandler.class })
-	@ConditionalOnProperty(prefix = "spring.graphql.websocket", name = "path")
-	public static class WebSocketConfiguration {
-
-		@Bean
-		@ConditionalOnMissingBean
-		public GraphQlWebSocketHandler graphQlWebSocketHandler(WebGraphQlHandler webGraphQlHandler,
-				GraphQlProperties properties, HttpMessageConverters converters) {
-
-			return new GraphQlWebSocketHandler(webGraphQlHandler, getJsonConverter(converters),
-					properties.getWebsocket().getConnectionInitTimeout());
-		}
-
-		@SuppressWarnings("unchecked")
-		private static GenericHttpMessageConverter<Object> getJsonConverter(HttpMessageConverters converters) {
-			return converters.getConverters().stream()
-					.filter((candidate) -> candidate.canRead(Map.class, MediaType.APPLICATION_JSON)).findFirst()
-					.map((converter) -> (GenericHttpMessageConverter<Object>) converter)
-					.orElseThrow(() -> new IllegalStateException("No JSON converter"));
-		}
-
-		@Bean
-		public HandlerMapping graphQlWebSocketMapping(GraphQlWebSocketHandler handler, GraphQlProperties properties) {
-			String path = properties.getWebsocket().getPath();
-			if (logger.isInfoEnabled()) {
-				logger.info("GraphQL endpoint WebSocket " + path);
-			}
-			WebSocketHandlerMapping mapping = new WebSocketHandlerMapping();
-			mapping.setWebSocketUpgradeMatch(true);
-			mapping.setUrlMap(Collections.singletonMap(path,
-					new WebSocketHttpRequestHandler(handler, new DefaultHandshakeHandler())));
-			mapping.setOrder(2); // Ahead of HTTP endpoint ("routerFunctionMapping" bean)
-			return mapping;
-		}
-
-	}
+    private static MediaType[] SUPPORTED_MEDIA_TYPES = new MediaType[] { MediaType.APPLICATION_GRAPHQL,
+            MediaType.APPLICATION_JSON };
+
+    @Bean
+    @ConditionalOnMissingBean
+    public GraphQlHttpHandler graphQlHttpHandler(final WebGraphQlHandler webGraphQlHandler) {
+        return new GraphQlHttpHandler(webGraphQlHandler);
+    }
+
+    @Bean
+    @ConditionalOnMissingBean
+    public WebGraphQlHandler webGraphQlHandler(final ExecutionGraphQlService service,
+            final ObjectProvider<WebGraphQlInterceptor> interceptorsProvider,
+            final ObjectProvider<ThreadLocalAccessor> accessorsProvider) {
+        return WebGraphQlHandler.builder(service)
+                .interceptors(interceptorsProvider.orderedStream().collect(Collectors.toList()))
+                .threadLocalAccessors(accessorsProvider.orderedStream().collect(Collectors.toList())).build();
+    }
+
+    @Bean
+    public RouterFunction<ServerResponse> graphQlRouterFunction(final GraphQlHttpHandler httpHandler,
+            final GraphQlSource graphQlSource, final GraphQlProperties properties) {
+        String path = properties.getPath();
+        logger.info(LogMessage.format("GraphQL endpoint HTTP POST %s", path));
+        RouterFunctions.Builder builder = RouterFunctions.route();
+        builder = builder.GET(path, this::onlyAllowPost);
+        builder = builder.POST(path, RequestPredicates.contentType(SUPPORTED_MEDIA_TYPES)
+                .and(RequestPredicates.accept(SUPPORTED_MEDIA_TYPES)), httpHandler::handleRequest);
+        if (properties.getGraphiql().isEnabled()) {
+            GraphiQlHandler graphiQLHandler = new GraphiQlHandler(path, properties.getWebsocket().getPath());
+            builder = builder.GET(properties.getGraphiql().getPath(), graphiQLHandler::handleRequest);
+        }
+        if (properties.getSchema().getPrinter().isEnabled()) {
+            SchemaHandler schemaHandler = new SchemaHandler(graphQlSource);
+            builder = builder.GET(path + "/schema", schemaHandler::handleRequest);
+        }
+        return builder.build();
+    }
+
+    private ServerResponse onlyAllowPost(final ServerRequest request) {
+        return ServerResponse.status(HttpStatus.METHOD_NOT_ALLOWED).headers(this::onlyAllowPost).build();
+    }
+
+    private void onlyAllowPost(final HttpHeaders headers) {
+        headers.setAllow(Collections.singleton(HttpMethod.POST));
+    }
+
+    @Configuration(proxyBeanMethods = false)
+    public static class GraphQlEndpointCorsConfiguration implements WebMvcConfigurer {
+
+        final GraphQlProperties graphQlProperties;
+
+        final GraphQlCorsProperties corsProperties;
+
+        public GraphQlEndpointCorsConfiguration(final GraphQlProperties graphQlProps, final GraphQlCorsProperties corsProps) {
+            this.graphQlProperties = graphQlProps;
+            this.corsProperties = corsProps;
+        }
+
+        @Override
+        public void addCorsMappings(final CorsRegistry registry) {
+            CorsConfiguration configuration = this.corsProperties.toCorsConfiguration();
+            if (configuration != null) {
+                registry.addMapping(this.graphQlProperties.getPath()).combine(configuration);
+            }
+        }
+
+    }
+
+    @Configuration(proxyBeanMethods = false)
+    @ConditionalOnClass({ ServerContainer.class, WebSocketHandler.class })
+    @ConditionalOnProperty(prefix = "spring.graphql.websocket", name = "path")
+    public static class WebSocketConfiguration {
+
+        @Bean
+        @ConditionalOnMissingBean
+        public GraphQlWebSocketHandler graphQlWebSocketHandler(final WebGraphQlHandler webGraphQlHandler,
+                final GraphQlProperties properties, final HttpMessageConverters converters) {
+            return new GraphQlWebSocketHandler(webGraphQlHandler, getJsonConverter(converters),
+                    properties.getWebsocket().getConnectionInitTimeout());
+        }
+
+        private GenericHttpMessageConverter<Object> getJsonConverter(final HttpMessageConverters converters) {
+            return converters.getConverters().stream().filter(this::canReadJsonMap).findFirst()
+                    .map(this::asGenericHttpMessageConverter)
+                    .orElseThrow(() -> new IllegalStateException("No JSON converter"));
+        }
+
+        private boolean canReadJsonMap(final HttpMessageConverter<?> candidate) {
+            return candidate.canRead(Map.class, MediaType.APPLICATION_JSON);
+        }
+
+        @SuppressWarnings("unchecked")
+        private GenericHttpMessageConverter<Object> asGenericHttpMessageConverter(final HttpMessageConverter<?> converter) {
+            return (GenericHttpMessageConverter<Object>) converter;
+        }
+
+        @Bean
+        public HandlerMapping graphQlWebSocketMapping(final GraphQlWebSocketHandler handler, final GraphQlProperties properties) {
+            String path = properties.getWebsocket().getPath();
+            logger.info(LogMessage.format("GraphQL endpoint WebSocket %s", path));
+            WebSocketHandlerMapping mapping = new WebSocketHandlerMapping();
+            mapping.setWebSocketUpgradeMatch(true);
+            mapping.setUrlMap(Collections.singletonMap(path,
+                    handler.asWebSocketHttpRequestHandler(new DefaultHandshakeHandler())));
+            mapping.setOrder(2); // Ahead of HTTP endpoint ("routerFunctionMapping" bean)
+            return mapping;
+        }
+
+    }
 
 }