mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-05-03 03:43:54 +01:00
Consider Jackson 2 in GraphQL RSocket auto-configuration
See gh-47688
This commit is contained in:
committed by
Phillip Webb
parent
50a73b8dfe
commit
2264b77c6f
@@ -28,10 +28,11 @@ dependencies {
|
|||||||
api(project(":core:spring-boot"))
|
api(project(":core:spring-boot"))
|
||||||
api("org.springframework.graphql:spring-graphql")
|
api("org.springframework.graphql:spring-graphql")
|
||||||
|
|
||||||
implementation(project(":module:spring-boot-jackson"))
|
|
||||||
|
|
||||||
optional(project(":core:spring-boot-autoconfigure"))
|
optional(project(":core:spring-boot-autoconfigure"))
|
||||||
optional(project(":module:spring-boot-http-converter"))
|
optional(project(":module:spring-boot-http-converter"))
|
||||||
|
optional(project(":module:spring-boot-jackson"))
|
||||||
|
optional(project(":module:spring-boot-jackson2"))
|
||||||
optional(project(":module:spring-boot-micrometer-observation"))
|
optional(project(":module:spring-boot-micrometer-observation"))
|
||||||
optional(project(":module:spring-boot-rsocket"))
|
optional(project(":module:spring-boot-rsocket"))
|
||||||
optional(project(":module:spring-boot-security"))
|
optional(project(":module:spring-boot-security"))
|
||||||
|
|||||||
+62
-3
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.springframework.boot.graphql.autoconfigure.rsocket;
|
package org.springframework.boot.graphql.autoconfigure.rsocket;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import graphql.GraphQL;
|
import graphql.GraphQL;
|
||||||
import io.rsocket.core.RSocketServer;
|
import io.rsocket.core.RSocketServer;
|
||||||
import reactor.netty.http.server.HttpServer;
|
import reactor.netty.http.server.HttpServer;
|
||||||
@@ -24,12 +25,17 @@ import tools.jackson.databind.json.JsonMapper;
|
|||||||
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.boot.graphql.autoconfigure.GraphQlAutoConfiguration;
|
import org.springframework.boot.graphql.autoconfigure.GraphQlAutoConfiguration;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Conditional;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.codec.Encoder;
|
||||||
import org.springframework.graphql.ExecutionGraphQlService;
|
import org.springframework.graphql.ExecutionGraphQlService;
|
||||||
import org.springframework.graphql.data.method.annotation.support.AnnotatedControllerConfigurer;
|
import org.springframework.graphql.data.method.annotation.support.AnnotatedControllerConfigurer;
|
||||||
import org.springframework.graphql.execution.GraphQlSource;
|
import org.springframework.graphql.execution.GraphQlSource;
|
||||||
@@ -46,7 +52,9 @@ import org.springframework.messaging.rsocket.annotation.support.RSocketMessageHa
|
|||||||
* @since 4.0.0
|
* @since 4.0.0
|
||||||
*/
|
*/
|
||||||
@AutoConfiguration(after = GraphQlAutoConfiguration.class,
|
@AutoConfiguration(after = GraphQlAutoConfiguration.class,
|
||||||
afterName = "org.springframework.boot.rsocket.autoconfigure.RSocketMessagingAutoConfiguration")
|
afterName = { "org.springframework.boot.rsocket.autoconfigure.RSocketMessagingAutoConfiguration",
|
||||||
|
"org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration",
|
||||||
|
"org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration" })
|
||||||
@ConditionalOnClass({ GraphQL.class, GraphQlSource.class, RSocketServer.class, HttpServer.class })
|
@ConditionalOnClass({ GraphQL.class, GraphQlSource.class, RSocketServer.class, HttpServer.class })
|
||||||
@ConditionalOnBean({ RSocketMessageHandler.class, AnnotatedControllerConfigurer.class })
|
@ConditionalOnBean({ RSocketMessageHandler.class, AnnotatedControllerConfigurer.class })
|
||||||
@ConditionalOnProperty("spring.graphql.rsocket.mapping")
|
@ConditionalOnProperty("spring.graphql.rsocket.mapping")
|
||||||
@@ -55,9 +63,9 @@ public final class GraphQlRSocketAutoConfiguration {
|
|||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
GraphQlRSocketHandler graphQlRSocketHandler(ExecutionGraphQlService graphQlService,
|
GraphQlRSocketHandler graphQlRSocketHandler(ExecutionGraphQlService graphQlService,
|
||||||
ObjectProvider<RSocketGraphQlInterceptor> interceptors, JsonMapper jsonMapper) {
|
ObjectProvider<RSocketGraphQlInterceptor> interceptors, JsonEncoderSupplier jsonEncoderSupplier) {
|
||||||
return new GraphQlRSocketHandler(graphQlService, interceptors.orderedStream().toList(),
|
return new GraphQlRSocketHandler(graphQlService, interceptors.orderedStream().toList(),
|
||||||
new JacksonJsonEncoder(jsonMapper));
|
jsonEncoderSupplier.jsonEncoder());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@@ -66,4 +74,55 @@ public final class GraphQlRSocketAutoConfiguration {
|
|||||||
return new GraphQlRSocketController(handler);
|
return new GraphQlRSocketController(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface JsonEncoderSupplier {
|
||||||
|
|
||||||
|
Encoder<?> jsonEncoder();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
@ConditionalOnBean(JsonMapper.class)
|
||||||
|
@ConditionalOnProperty(name = "spring.graphql.rsocket.preferred-json-mapper", havingValue = "jackson",
|
||||||
|
matchIfMissing = true)
|
||||||
|
static class JacksonJsonEncoderSupplierConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
JsonEncoderSupplier jacksonJsonEncoderSupplier(JsonMapper jsonMapper) {
|
||||||
|
return () -> new JacksonJsonEncoder(jsonMapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
@ConditionalOnBean(ObjectMapper.class)
|
||||||
|
@Conditional(NoJacksonOrJackson2Preferred.class)
|
||||||
|
@Deprecated(since = "4.0.0", forRemoval = true)
|
||||||
|
@SuppressWarnings("removal")
|
||||||
|
static class Jackson2JsonEncoderSupplierConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
JsonEncoderSupplier jackson2JsonEncoderSupplier(ObjectMapper objectMapper) {
|
||||||
|
return () -> new org.springframework.http.codec.json.Jackson2JsonEncoder(objectMapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static class NoJacksonOrJackson2Preferred extends AnyNestedCondition {
|
||||||
|
|
||||||
|
NoJacksonOrJackson2Preferred() {
|
||||||
|
super(ConfigurationPhase.PARSE_CONFIGURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConditionalOnMissingClass("tools.jackson.databind.json.JsonMapper")
|
||||||
|
static class NoJackson {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConditionalOnProperty(name = "spring.graphql.rsocket.preferred-json-mapper", havingValue = "jackson2")
|
||||||
|
static class Jackson2Preferred {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+22
@@ -37,6 +37,12 @@
|
|||||||
"since": "3.5.0"
|
"since": "3.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.graphql.rsocket.preferred-json-mapper",
|
||||||
|
"type": "java.lang.String",
|
||||||
|
"defaultValue": "jackson",
|
||||||
|
"description": "Preferred JSON mapper to use. By default, auto-detected according to the environment. Supported values are 'jackson' and 'jackson2' (deprecated)."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "spring.graphql.schema.file-extensions",
|
"name": "spring.graphql.schema.file-extensions",
|
||||||
"defaultValue": ".graphqls,.gqls"
|
"defaultValue": ".graphqls,.gqls"
|
||||||
@@ -95,6 +101,22 @@
|
|||||||
"name": "any"
|
"name": "any"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.graphql.rsocket.preferred-json-mapper",
|
||||||
|
"values": [
|
||||||
|
{
|
||||||
|
"value": "jackson"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "jackson2"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"providers": [
|
||||||
|
{
|
||||||
|
"name": "any"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
+31
@@ -22,18 +22,22 @@ import java.util.function.Consumer;
|
|||||||
|
|
||||||
import graphql.schema.idl.TypeRuntimeWiring;
|
import graphql.schema.idl.TypeRuntimeWiring;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener;
|
||||||
import org.springframework.boot.graphql.autoconfigure.GraphQlAutoConfiguration;
|
import org.springframework.boot.graphql.autoconfigure.GraphQlAutoConfiguration;
|
||||||
import org.springframework.boot.graphql.autoconfigure.GraphQlTestDataFetchers;
|
import org.springframework.boot.graphql.autoconfigure.GraphQlTestDataFetchers;
|
||||||
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
|
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
|
||||||
|
import org.springframework.boot.logging.LogLevel;
|
||||||
import org.springframework.boot.reactor.netty.NettyReactiveWebServerFactory;
|
import org.springframework.boot.reactor.netty.NettyReactiveWebServerFactory;
|
||||||
import org.springframework.boot.reactor.netty.NettyRouteProvider;
|
import org.springframework.boot.reactor.netty.NettyRouteProvider;
|
||||||
import org.springframework.boot.rsocket.autoconfigure.RSocketMessagingAutoConfiguration;
|
import org.springframework.boot.rsocket.autoconfigure.RSocketMessagingAutoConfiguration;
|
||||||
import org.springframework.boot.rsocket.autoconfigure.RSocketServerAutoConfiguration;
|
import org.springframework.boot.rsocket.autoconfigure.RSocketServerAutoConfiguration;
|
||||||
import org.springframework.boot.rsocket.autoconfigure.RSocketStrategiesAutoConfiguration;
|
import org.springframework.boot.rsocket.autoconfigure.RSocketStrategiesAutoConfiguration;
|
||||||
import org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer;
|
import org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer;
|
||||||
|
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||||
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
|
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
|
||||||
import org.springframework.boot.testsupport.classpath.resources.WithResource;
|
import org.springframework.boot.testsupport.classpath.resources.WithResource;
|
||||||
import org.springframework.boot.web.server.context.ServerPortInfoApplicationContextInitializer;
|
import org.springframework.boot.web.server.context.ServerPortInfoApplicationContextInitializer;
|
||||||
@@ -99,6 +103,33 @@ class GraphQlRSocketAutoConfigurationTests {
|
|||||||
testWithRSocketWebSocket(this::assertThatSimpleQueryWorks);
|
testWithRSocketWebSocket(this::assertThatSimpleQueryWorks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void usesJacksonByDefault() {
|
||||||
|
this.contextRunner.run((context) -> assertThat(context).hasBean("jacksonJsonEncoderSupplier"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Deprecated(since = "4.0.0", forRemoval = true)
|
||||||
|
@SuppressWarnings("removal")
|
||||||
|
void usesJackson2WhenItIsPreferred() {
|
||||||
|
this.contextRunner.withPropertyValues("spring.graphql.rsocket.preferred-json-mapper=jackson2")
|
||||||
|
.withConfiguration(AutoConfigurations
|
||||||
|
.of(org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.class))
|
||||||
|
.run((context) -> assertThat(context).hasBean("jackson2JsonEncoderSupplier"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Deprecated(since = "4.0.0", forRemoval = true)
|
||||||
|
@SuppressWarnings("removal")
|
||||||
|
void usesJackson2WhenJacksonIsAbsent() {
|
||||||
|
this.contextRunner
|
||||||
|
.withClassLoader(new FilteredClassLoader(Thread.currentThread().getContextClassLoader(), JsonMapper.class))
|
||||||
|
.withConfiguration(AutoConfigurations
|
||||||
|
.of(org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.class))
|
||||||
|
.withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO))
|
||||||
|
.run((context) -> assertThat(context).hasBean("jackson2JsonEncoderSupplier"));
|
||||||
|
}
|
||||||
|
|
||||||
private void assertThatSimpleQueryWorks(RSocketGraphQlClient client) {
|
private void assertThatSimpleQueryWorks(RSocketGraphQlClient client) {
|
||||||
String document = "{ bookById(id: \"book-1\"){ id name pageCount author } }";
|
String document = "{ bookById(id: \"book-1\"){ id name pageCount author } }";
|
||||||
String bookName = client.document(document)
|
String bookName = client.document(document)
|
||||||
|
|||||||
Reference in New Issue
Block a user