diff --git a/spring-boot-project/spring-boot-autoconfigure/pom.xml b/spring-boot-project/spring-boot-autoconfigure/pom.xml
index b794fcce9cc..8b671d16868 100755
--- a/spring-boot-project/spring-boot-autoconfigure/pom.xml
+++ b/spring-boot-project/spring-boot-autoconfigure/pom.xml
@@ -42,6 +42,11 @@
jackson-databind
true
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-cbor
+ true
+
com.fasterxml.jackson.dataformat
jackson-dataformat-xml
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/rsocket/RSocketStrategiesAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/rsocket/RSocketStrategiesAutoConfiguration.java
index ce987ad7bb4..49e26c8804a 100644
--- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/rsocket/RSocketStrategiesAutoConfiguration.java
+++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/rsocket/RSocketStrategiesAutoConfiguration.java
@@ -17,6 +17,7 @@
package org.springframework.boot.autoconfigure.rsocket;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.cbor.CBORFactory;
import io.netty.buffer.PooledByteBufAllocator;
import io.rsocket.RSocketFactory;
@@ -34,8 +35,11 @@ import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.NettyDataBufferFactory;
import org.springframework.http.MediaType;
+import org.springframework.http.codec.cbor.Jackson2CborDecoder;
+import org.springframework.http.codec.cbor.Jackson2CborEncoder;
import org.springframework.http.codec.json.Jackson2JsonDecoder;
import org.springframework.http.codec.json.Jackson2JsonEncoder;
+import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.messaging.rsocket.RSocketStrategies;
/**
@@ -56,20 +60,41 @@ public class RSocketStrategiesAutoConfiguration {
ObjectProvider customizers) {
RSocketStrategies.Builder builder = RSocketStrategies.builder();
builder.reactiveAdapterStrategy(ReactiveAdapterRegistry.getSharedInstance());
- customizers.stream().forEach((customizer) -> customizer.customize(builder));
+ customizers.orderedStream()
+ .forEach((customizer) -> customizer.customize(builder));
builder.dataBufferFactory(
new NettyDataBufferFactory(PooledByteBufAllocator.DEFAULT));
return builder.build();
}
@Configuration(proxyBeanMethods = false)
- @ConditionalOnClass(ObjectMapper.class)
- protected static class JacksonStrategyConfiguration {
+ @ConditionalOnClass({ ObjectMapper.class, CBORFactory.class })
+ protected static class JacksonCborStrategyConfiguration {
@Bean
@Order(0)
+ @ConditionalOnBean(Jackson2ObjectMapperBuilder.class)
+ public RSocketStrategiesCustomizer jacksonCborStrategyCustomizer(
+ Jackson2ObjectMapperBuilder builder) {
+ return (strategy) -> {
+ ObjectMapper objectMapper = builder.factory(new CBORFactory()).build();
+ MediaType[] supportedTypes = new MediaType[] {
+ new MediaType("application", "cbor") };
+ strategy.decoder(new Jackson2CborDecoder(objectMapper, supportedTypes));
+ strategy.encoder(new Jackson2CborEncoder(objectMapper, supportedTypes));
+ };
+ }
+
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @ConditionalOnClass(ObjectMapper.class)
+ protected static class JacksonJsonStrategyConfiguration {
+
+ @Bean
+ @Order(1)
@ConditionalOnBean(ObjectMapper.class)
- public RSocketStrategiesCustomizer jacksonStrategyCustomizer(
+ public RSocketStrategiesCustomizer jacksonJsonStrategyCustomizer(
ObjectMapper objectMapper) {
return (strategy) -> {
MediaType[] supportedTypes = new MediaType[] { MediaType.APPLICATION_JSON,
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/rsocket/RSocketStrategiesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/rsocket/RSocketStrategiesAutoConfigurationTests.java
index 55545b6d120..ea34cb74a75 100644
--- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/rsocket/RSocketStrategiesAutoConfigurationTests.java
+++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/rsocket/RSocketStrategiesAutoConfigurationTests.java
@@ -26,8 +26,11 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.codec.CharSequenceEncoder;
import org.springframework.core.codec.StringDecoder;
+import org.springframework.http.codec.cbor.Jackson2CborDecoder;
+import org.springframework.http.codec.cbor.Jackson2CborEncoder;
import org.springframework.http.codec.json.Jackson2JsonDecoder;
import org.springframework.http.codec.json.Jackson2JsonEncoder;
+import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.messaging.rsocket.RSocketStrategies;
import static org.assertj.core.api.Assertions.assertThat;
@@ -48,10 +51,16 @@ public class RSocketStrategiesAutoConfigurationTests {
this.contextRunner.run((context) -> {
assertThat(context).getBeans(RSocketStrategies.class).hasSize(1);
RSocketStrategies strategies = context.getBean(RSocketStrategies.class);
- assertThat(strategies.decoders()).hasSize(1)
- .hasOnlyElementsOfType(Jackson2JsonDecoder.class);
- assertThat(strategies.encoders()).hasSize(1)
- .hasOnlyElementsOfType(Jackson2JsonEncoder.class);
+ assertThat(strategies.decoders()).hasSize(2);
+ assertThat(strategies.decoders().get(0))
+ .isInstanceOf(Jackson2CborDecoder.class);
+ assertThat(strategies.decoders().get(1))
+ .isInstanceOf(Jackson2JsonDecoder.class);
+ assertThat(strategies.encoders()).hasSize(2);
+ assertThat(strategies.encoders().get(0))
+ .isInstanceOf(Jackson2CborEncoder.class);
+ assertThat(strategies.encoders().get(1))
+ .isInstanceOf(Jackson2JsonEncoder.class);
});
}
@@ -71,9 +80,9 @@ public class RSocketStrategiesAutoConfigurationTests {
assertThat(context).getBeans(RSocketStrategies.class).hasSize(1);
RSocketStrategies strategies = context
.getBean(RSocketStrategies.class);
- assertThat(strategies.decoders()).hasSize(2)
+ assertThat(strategies.decoders()).hasSize(3)
.hasAtLeastOneElementOfType(StringDecoder.class);
- assertThat(strategies.encoders()).hasSize(2)
+ assertThat(strategies.encoders()).hasSize(3)
.hasAtLeastOneElementOfType(CharSequenceEncoder.class);
});
}
@@ -86,6 +95,11 @@ public class RSocketStrategiesAutoConfigurationTests {
return new ObjectMapper();
}
+ @Bean
+ public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
+ return new Jackson2ObjectMapperBuilder();
+ }
+
}
@Configuration
diff --git a/spring-boot-project/spring-boot-docs/pom.xml b/spring-boot-project/spring-boot-docs/pom.xml
index 61dddbe0817..849c3ae164f 100644
--- a/spring-boot-project/spring-boot-docs/pom.xml
+++ b/spring-boot-project/spring-boot-docs/pom.xml
@@ -135,6 +135,11 @@
jackson-datatype-joda
true
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-cbor
+ true
+
com.fasterxml.jackson.dataformat
jackson-dataformat-xml
diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
index b595d58d40e..15550b8e3c5 100644
--- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
+++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
@@ -3483,6 +3483,22 @@ The following code shows a typical `@Controller`:
}
----
+[[boot-features-rsocket-strategies-auto-configuration]]
+=== RSocket Strategies Auto-configuration
+Spring Boot auto-configures an `RSocketStrategies` bean that provides all the required
+infrastructure for encoding and decoding RSocket payloads. By default, the
+auto-configuration will try to configure the following (in order):
+
+1. https://cbor.io/[CBOR] codecs with Jackson
+2. JSON codecs with Jackson
+
+The `spring-boot-starter-rsocket` Starter provides both dependencies.
+
+Developers can customize the `RSocketStrategies` component by creating beans that
+implement the `RSocketStrategiesCustomizer` interface. Note that their `@Order` is
+important, as it determines the order of codecs.
+
+
[[boot-features-rsocket-server-auto-configuration]]
=== RSocket server Auto-configuration
Spring Boot provides auto-configuration for RSocket servers. The required dependencies
diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-rsocket/pom.xml b/spring-boot-project/spring-boot-starters/spring-boot-starter-rsocket/pom.xml
index 0d685878de2..700bcc541d1 100644
--- a/spring-boot-project/spring-boot-starters/spring-boot-starter-rsocket/pom.xml
+++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-rsocket/pom.xml
@@ -54,5 +54,9 @@
org.springframework.boot
spring-boot-starter-json
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-cbor
+