mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-17 12:09:16 +00:00
Consider Jackson 2 in RSocket auto-configuration
See gh-47688
This commit is contained in:
committed by
Phillip Webb
parent
2264b77c6f
commit
dee32e0914
@@ -33,10 +33,12 @@ dependencies {
|
||||
|
||||
optional(project(":core:spring-boot-autoconfigure"))
|
||||
optional(project(":module:spring-boot-jackson"))
|
||||
optional(project(":module:spring-boot-jackson2"))
|
||||
optional(project(":module:spring-boot-reactor-netty"))
|
||||
optional("io.rsocket:rsocket-transport-netty")
|
||||
optional("org.springframework:spring-web")
|
||||
optional("tools.jackson.dataformat:jackson-dataformat-cbor")
|
||||
optional("com.fasterxml.jackson.dataformat:jackson-dataformat-cbor")
|
||||
|
||||
testImplementation(project(":core:spring-boot-test"))
|
||||
testImplementation(project(":test-support:spring-boot-test-support"))
|
||||
|
||||
+107
-24
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.boot.rsocket.autoconfigure;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.dataformat.cbor.CBORFactory;
|
||||
import io.netty.buffer.PooledByteBufAllocator;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
import tools.jackson.dataformat.cbor.CBORMapper;
|
||||
@@ -23,11 +25,15 @@ import tools.jackson.dataformat.cbor.CBORMapper;
|
||||
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.rsocket.messaging.RSocketStrategiesCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -45,7 +51,8 @@ import org.springframework.web.util.pattern.PathPatternRouteMatcher;
|
||||
* @author Brian Clozel
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@AutoConfiguration(afterName = "org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration")
|
||||
@AutoConfiguration(afterName = { "org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration",
|
||||
"org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration" })
|
||||
@ConditionalOnClass({ io.rsocket.RSocket.class, RSocketStrategies.class, PooledByteBufAllocator.class })
|
||||
public final class RSocketStrategiesAutoConfiguration {
|
||||
|
||||
@@ -63,38 +70,114 @@ public final class RSocketStrategiesAutoConfiguration {
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(CBORMapper.class)
|
||||
@ConditionalOnBean(CBORMapper.class)
|
||||
protected static class JacksonCborStrategyConfiguration {
|
||||
@ConditionalOnProperty(name = "spring.rsocket.preferred-mapper", havingValue = "jackson", matchIfMissing = true)
|
||||
static class JacksonStrategyConfiguration {
|
||||
|
||||
private static final MediaType[] SUPPORTED_TYPES = { MediaType.APPLICATION_CBOR };
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(CBORMapper.class)
|
||||
@ConditionalOnBean(CBORMapper.class)
|
||||
static class JacksonCborStrategyConfiguration {
|
||||
|
||||
private static final MediaType[] SUPPORTED_TYPES = { MediaType.APPLICATION_CBOR };
|
||||
|
||||
@Bean
|
||||
@Order(0)
|
||||
RSocketStrategiesCustomizer jacksonCborRSocketStrategyCustomizer(CBORMapper cborMapper) {
|
||||
return (strategy) -> {
|
||||
strategy.decoder(new JacksonCborDecoder(cborMapper, SUPPORTED_TYPES));
|
||||
strategy.encoder(new JacksonCborEncoder(cborMapper, SUPPORTED_TYPES));
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(JsonMapper.class)
|
||||
static class JacksonJsonStrategyConfiguration {
|
||||
|
||||
private static final MediaType[] SUPPORTED_TYPES = { MediaType.APPLICATION_JSON,
|
||||
new MediaType("application", "*+json") };
|
||||
|
||||
@Bean
|
||||
@Order(1)
|
||||
@ConditionalOnBean(JsonMapper.class)
|
||||
RSocketStrategiesCustomizer jacksonJsonRSocketStrategyCustomizer(JsonMapper jsonMapper) {
|
||||
return (strategy) -> {
|
||||
strategy.decoder(new JacksonJsonDecoder(jsonMapper, SUPPORTED_TYPES));
|
||||
strategy.encoder(new JacksonJsonEncoder(jsonMapper, SUPPORTED_TYPES));
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(0)
|
||||
RSocketStrategiesCustomizer jacksonCborRSocketStrategyCustomizer(CBORMapper cborMapper) {
|
||||
return (strategy) -> {
|
||||
strategy.decoder(new JacksonCborDecoder(cborMapper, SUPPORTED_TYPES));
|
||||
strategy.encoder(new JacksonCborEncoder(cborMapper, SUPPORTED_TYPES));
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(JsonMapper.class)
|
||||
@ConditionalOnBean(JsonMapper.class)
|
||||
protected static class JacksonJsonStrategyConfiguration {
|
||||
@Conditional(NoJacksonOrJackson2Preferred.class)
|
||||
@SuppressWarnings("removal")
|
||||
@Deprecated(since = "4.0.0", forRemoval = true)
|
||||
static class Jackson2StrategyConfiguration {
|
||||
|
||||
private static final MediaType[] SUPPORTED_TYPES = { MediaType.APPLICATION_JSON,
|
||||
new MediaType("application", "*+json") };
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ ObjectMapper.class, CBORFactory.class })
|
||||
static class Jackson2CborStrategyConfiguration {
|
||||
|
||||
private static final MediaType[] SUPPORTED_TYPES = { MediaType.APPLICATION_CBOR };
|
||||
|
||||
@Bean
|
||||
@Order(0)
|
||||
@ConditionalOnBean(org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.class)
|
||||
RSocketStrategiesCustomizer jackson2CborRSocketStrategyCustomizer(
|
||||
org.springframework.http.converter.json.Jackson2ObjectMapperBuilder builder) {
|
||||
return (strategy) -> {
|
||||
ObjectMapper objectMapper = builder.createXmlMapper(false)
|
||||
.factory(new com.fasterxml.jackson.dataformat.cbor.CBORFactory())
|
||||
.build();
|
||||
strategy.decoder(
|
||||
new org.springframework.http.codec.cbor.Jackson2CborDecoder(objectMapper, SUPPORTED_TYPES));
|
||||
strategy.encoder(
|
||||
new org.springframework.http.codec.cbor.Jackson2CborEncoder(objectMapper, SUPPORTED_TYPES));
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnClass(ObjectMapper.class)
|
||||
static class Jackson2JsonStrategyConfiguration {
|
||||
|
||||
private static final MediaType[] SUPPORTED_TYPES = { MediaType.APPLICATION_JSON,
|
||||
new MediaType("application", "*+json") };
|
||||
|
||||
@Bean
|
||||
@Order(1)
|
||||
@ConditionalOnBean(ObjectMapper.class)
|
||||
RSocketStrategiesCustomizer jackson2JsonRSocketStrategyCustomizer(ObjectMapper objectMapper) {
|
||||
return (strategy) -> {
|
||||
strategy.decoder(
|
||||
new org.springframework.http.codec.json.Jackson2JsonDecoder(objectMapper, SUPPORTED_TYPES));
|
||||
strategy.encoder(
|
||||
new org.springframework.http.codec.json.Jackson2JsonEncoder(objectMapper, SUPPORTED_TYPES));
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class NoJacksonOrJackson2Preferred extends AnyNestedCondition {
|
||||
|
||||
NoJacksonOrJackson2Preferred() {
|
||||
super(ConfigurationPhase.PARSE_CONFIGURATION);
|
||||
}
|
||||
|
||||
@ConditionalOnMissingClass("tools.jackson.databind.json.JsonMapper")
|
||||
static class NoJackson {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(name = "spring.rsocket.preferred-mapper", havingValue = "jackson2")
|
||||
static class Jackson2Preferred {
|
||||
|
||||
@Bean
|
||||
@Order(1)
|
||||
RSocketStrategiesCustomizer jacksonJsonRSocketStrategyCustomizer(JsonMapper jsonMapper) {
|
||||
return (strategy) -> {
|
||||
strategy.decoder(new JacksonJsonDecoder(jsonMapper, SUPPORTED_TYPES));
|
||||
strategy.encoder(new JacksonJsonEncoder(jsonMapper, SUPPORTED_TYPES));
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+25
-1
@@ -1,4 +1,28 @@
|
||||
{
|
||||
"properties": [
|
||||
{
|
||||
"name": "spring.rsocket.preferred-mapper",
|
||||
"type": "java.lang.String",
|
||||
"defaultValue": "jackson",
|
||||
"description": "Preferred JSON and CBOR mapper to use. By default, auto-detected according to the environment. Supported values are 'jackson' and 'jackson2' (deprecated)."
|
||||
}
|
||||
],
|
||||
"hints": [
|
||||
{
|
||||
"name": "spring.rsocket.preferred-mapper",
|
||||
"values": [
|
||||
{
|
||||
"value": "jackson"
|
||||
},
|
||||
{
|
||||
"value": "jackson2"
|
||||
}
|
||||
],
|
||||
"providers": [
|
||||
{
|
||||
"name": "any"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
+39
@@ -22,6 +22,7 @@ import tools.jackson.dataformat.cbor.CBORMapper;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.rsocket.messaging.RSocketStrategiesCustomizer;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -82,6 +83,44 @@ class RSocketStrategiesAutoConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@Deprecated(since = "4.0.0", forRemoval = true)
|
||||
@SuppressWarnings("removal")
|
||||
void shouldUseJackson2WhenPreferred() {
|
||||
this.contextRunner
|
||||
.withConfiguration(AutoConfigurations
|
||||
.of(org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.class))
|
||||
.withPropertyValues("spring.rsocket.preferred-mapper=jackson2")
|
||||
.run((context) -> {
|
||||
RSocketStrategies strategies = context.getBean(RSocketStrategies.class);
|
||||
assertThat(strategies.decoders())
|
||||
.hasAtLeastOneElementOfType(org.springframework.http.codec.cbor.Jackson2CborDecoder.class)
|
||||
.hasAtLeastOneElementOfType(org.springframework.http.codec.json.Jackson2JsonDecoder.class);
|
||||
assertThat(strategies.encoders())
|
||||
.hasAtLeastOneElementOfType(org.springframework.http.codec.cbor.Jackson2CborEncoder.class)
|
||||
.hasAtLeastOneElementOfType(org.springframework.http.codec.json.Jackson2JsonEncoder.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@Deprecated(since = "4.0.0", forRemoval = true)
|
||||
@SuppressWarnings("removal")
|
||||
void shouldUseJackson2WhenJacksonIsAbsent() {
|
||||
this.contextRunner
|
||||
.withConfiguration(AutoConfigurations
|
||||
.of(org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.class))
|
||||
.withClassLoader(new FilteredClassLoader(JsonMapper.class, CBORMapper.class))
|
||||
.run((context) -> {
|
||||
RSocketStrategies strategies = context.getBean(RSocketStrategies.class);
|
||||
assertThat(strategies.decoders())
|
||||
.hasAtLeastOneElementOfType(org.springframework.http.codec.cbor.Jackson2CborDecoder.class)
|
||||
.hasAtLeastOneElementOfType(org.springframework.http.codec.json.Jackson2JsonDecoder.class);
|
||||
assertThat(strategies.encoders())
|
||||
.hasAtLeastOneElementOfType(org.springframework.http.codec.cbor.Jackson2CborEncoder.class)
|
||||
.hasAtLeastOneElementOfType(org.springframework.http.codec.json.Jackson2JsonEncoder.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class UserStrategies {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user