mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-17 12:09:16 +00: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("org.springframework.graphql:spring-graphql")
|
||||
|
||||
implementation(project(":module:spring-boot-jackson"))
|
||||
|
||||
optional(project(":core:spring-boot-autoconfigure"))
|
||||
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-rsocket"))
|
||||
optional(project(":module:spring-boot-security"))
|
||||
|
||||
+62
-3
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.boot.graphql.autoconfigure.rsocket;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import graphql.GraphQL;
|
||||
import io.rsocket.core.RSocketServer;
|
||||
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.boot.autoconfigure.AutoConfiguration;
|
||||
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.ConditionalOnClass;
|
||||
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.graphql.autoconfigure.GraphQlAutoConfiguration;
|
||||
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.data.method.annotation.support.AnnotatedControllerConfigurer;
|
||||
import org.springframework.graphql.execution.GraphQlSource;
|
||||
@@ -46,7 +52,9 @@ import org.springframework.messaging.rsocket.annotation.support.RSocketMessageHa
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@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 })
|
||||
@ConditionalOnBean({ RSocketMessageHandler.class, AnnotatedControllerConfigurer.class })
|
||||
@ConditionalOnProperty("spring.graphql.rsocket.mapping")
|
||||
@@ -55,9 +63,9 @@ public final class GraphQlRSocketAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
GraphQlRSocketHandler graphQlRSocketHandler(ExecutionGraphQlService graphQlService,
|
||||
ObjectProvider<RSocketGraphQlInterceptor> interceptors, JsonMapper jsonMapper) {
|
||||
ObjectProvider<RSocketGraphQlInterceptor> interceptors, JsonEncoderSupplier jsonEncoderSupplier) {
|
||||
return new GraphQlRSocketHandler(graphQlService, interceptors.orderedStream().toList(),
|
||||
new JacksonJsonEncoder(jsonMapper));
|
||||
jsonEncoderSupplier.jsonEncoder());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -66,4 +74,55 @@ public final class GraphQlRSocketAutoConfiguration {
|
||||
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"
|
||||
}
|
||||
},
|
||||
{
|
||||
"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",
|
||||
"defaultValue": ".graphqls,.gqls"
|
||||
@@ -95,6 +101,22 @@
|
||||
"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 org.junit.jupiter.api.Test;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
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.GraphQlTestDataFetchers;
|
||||
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.NettyRouteProvider;
|
||||
import org.springframework.boot.rsocket.autoconfigure.RSocketMessagingAutoConfiguration;
|
||||
import org.springframework.boot.rsocket.autoconfigure.RSocketServerAutoConfiguration;
|
||||
import org.springframework.boot.rsocket.autoconfigure.RSocketStrategiesAutoConfiguration;
|
||||
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.testsupport.classpath.resources.WithResource;
|
||||
import org.springframework.boot.web.server.context.ServerPortInfoApplicationContextInitializer;
|
||||
@@ -99,6 +103,33 @@ class GraphQlRSocketAutoConfigurationTests {
|
||||
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) {
|
||||
String document = "{ bookById(id: \"book-1\"){ id name pageCount author } }";
|
||||
String bookName = client.document(document)
|
||||
|
||||
Reference in New Issue
Block a user