Skip to content

Commit e8d39a1

Browse files
committedMay 13, 2019
Add support for CBOR codecs in RSocket
This commit auto-configures CBOR (see https://cbor.io/) codecs in the RSocketStrategies, using Jackson binary format support. The required dependency is added to the rsocket starter. Binary codecs are well suited for RSocket payloads, so this codec is added first to the list of codecs (before the JSON one already supported). Closes spring-projectsgh-16830
1 parent 08cb836 commit e8d39a1

File tree

6 files changed

+79
-10
lines changed

6 files changed

+79
-10
lines changed
 

‎spring-boot-project/spring-boot-autoconfigure/pom.xml

+5
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@
4242
<artifactId>jackson-databind</artifactId>
4343
<optional>true</optional>
4444
</dependency>
45+
<dependency>
46+
<groupId>com.fasterxml.jackson.dataformat</groupId>
47+
<artifactId>jackson-dataformat-cbor</artifactId>
48+
<optional>true</optional>
49+
</dependency>
4550
<dependency>
4651
<groupId>com.fasterxml.jackson.dataformat</groupId>
4752
<artifactId>jackson-dataformat-xml</artifactId>

‎spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/rsocket/RSocketStrategiesAutoConfiguration.java

+29-4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.boot.autoconfigure.rsocket;
1818

1919
import com.fasterxml.jackson.databind.ObjectMapper;
20+
import com.fasterxml.jackson.dataformat.cbor.CBORFactory;
2021
import io.netty.buffer.PooledByteBufAllocator;
2122
import io.rsocket.RSocketFactory;
2223

@@ -34,8 +35,11 @@
3435
import org.springframework.core.annotation.Order;
3536
import org.springframework.core.io.buffer.NettyDataBufferFactory;
3637
import org.springframework.http.MediaType;
38+
import org.springframework.http.codec.cbor.Jackson2CborDecoder;
39+
import org.springframework.http.codec.cbor.Jackson2CborEncoder;
3740
import org.springframework.http.codec.json.Jackson2JsonDecoder;
3841
import org.springframework.http.codec.json.Jackson2JsonEncoder;
42+
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
3943
import org.springframework.messaging.rsocket.RSocketStrategies;
4044

4145
/**
@@ -56,20 +60,41 @@ public RSocketStrategies rSocketStrategies(
5660
ObjectProvider<RSocketStrategiesCustomizer> customizers) {
5761
RSocketStrategies.Builder builder = RSocketStrategies.builder();
5862
builder.reactiveAdapterStrategy(ReactiveAdapterRegistry.getSharedInstance());
59-
customizers.stream().forEach((customizer) -> customizer.customize(builder));
63+
customizers.orderedStream()
64+
.forEach((customizer) -> customizer.customize(builder));
6065
builder.dataBufferFactory(
6166
new NettyDataBufferFactory(PooledByteBufAllocator.DEFAULT));
6267
return builder.build();
6368
}
6469

6570
@Configuration(proxyBeanMethods = false)
66-
@ConditionalOnClass(ObjectMapper.class)
67-
protected static class JacksonStrategyConfiguration {
71+
@ConditionalOnClass({ ObjectMapper.class, CBORFactory.class })
72+
protected static class JacksonCborStrategyConfiguration {
6873

6974
@Bean
7075
@Order(0)
76+
@ConditionalOnBean(Jackson2ObjectMapperBuilder.class)
77+
public RSocketStrategiesCustomizer jacksonCborStrategyCustomizer(
78+
Jackson2ObjectMapperBuilder builder) {
79+
return (strategy) -> {
80+
ObjectMapper objectMapper = builder.factory(new CBORFactory()).build();
81+
MediaType[] supportedTypes = new MediaType[] {
82+
new MediaType("application", "cbor") };
83+
strategy.decoder(new Jackson2CborDecoder(objectMapper, supportedTypes));
84+
strategy.encoder(new Jackson2CborEncoder(objectMapper, supportedTypes));
85+
};
86+
}
87+
88+
}
89+
90+
@Configuration(proxyBeanMethods = false)
91+
@ConditionalOnClass(ObjectMapper.class)
92+
protected static class JacksonJsonStrategyConfiguration {
93+
94+
@Bean
95+
@Order(1)
7196
@ConditionalOnBean(ObjectMapper.class)
72-
public RSocketStrategiesCustomizer jacksonStrategyCustomizer(
97+
public RSocketStrategiesCustomizer jacksonJsonStrategyCustomizer(
7398
ObjectMapper objectMapper) {
7499
return (strategy) -> {
75100
MediaType[] supportedTypes = new MediaType[] { MediaType.APPLICATION_JSON,

‎spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/rsocket/RSocketStrategiesAutoConfigurationTests.java

+20-6
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,11 @@
2626
import org.springframework.context.annotation.Configuration;
2727
import org.springframework.core.codec.CharSequenceEncoder;
2828
import org.springframework.core.codec.StringDecoder;
29+
import org.springframework.http.codec.cbor.Jackson2CborDecoder;
30+
import org.springframework.http.codec.cbor.Jackson2CborEncoder;
2931
import org.springframework.http.codec.json.Jackson2JsonDecoder;
3032
import org.springframework.http.codec.json.Jackson2JsonEncoder;
33+
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
3134
import org.springframework.messaging.rsocket.RSocketStrategies;
3235

3336
import static org.assertj.core.api.Assertions.assertThat;
@@ -48,10 +51,16 @@ public void shouldCreateDefaultBeans() {
4851
this.contextRunner.run((context) -> {
4952
assertThat(context).getBeans(RSocketStrategies.class).hasSize(1);
5053
RSocketStrategies strategies = context.getBean(RSocketStrategies.class);
51-
assertThat(strategies.decoders()).hasSize(1)
52-
.hasOnlyElementsOfType(Jackson2JsonDecoder.class);
53-
assertThat(strategies.encoders()).hasSize(1)
54-
.hasOnlyElementsOfType(Jackson2JsonEncoder.class);
54+
assertThat(strategies.decoders()).hasSize(2);
55+
assertThat(strategies.decoders().get(0))
56+
.isInstanceOf(Jackson2CborDecoder.class);
57+
assertThat(strategies.decoders().get(1))
58+
.isInstanceOf(Jackson2JsonDecoder.class);
59+
assertThat(strategies.encoders()).hasSize(2);
60+
assertThat(strategies.encoders().get(0))
61+
.isInstanceOf(Jackson2CborEncoder.class);
62+
assertThat(strategies.encoders().get(1))
63+
.isInstanceOf(Jackson2JsonEncoder.class);
5564
});
5665
}
5766

@@ -71,9 +80,9 @@ public void shouldUseStrategiesCustomizer() {
7180
assertThat(context).getBeans(RSocketStrategies.class).hasSize(1);
7281
RSocketStrategies strategies = context
7382
.getBean(RSocketStrategies.class);
74-
assertThat(strategies.decoders()).hasSize(2)
83+
assertThat(strategies.decoders()).hasSize(3)
7584
.hasAtLeastOneElementOfType(StringDecoder.class);
76-
assertThat(strategies.encoders()).hasSize(2)
85+
assertThat(strategies.encoders()).hasSize(3)
7786
.hasAtLeastOneElementOfType(CharSequenceEncoder.class);
7887
});
7988
}
@@ -86,6 +95,11 @@ public ObjectMapper objectMapper() {
8695
return new ObjectMapper();
8796
}
8897

98+
@Bean
99+
public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
100+
return new Jackson2ObjectMapperBuilder();
101+
}
102+
89103
}
90104

91105
@Configuration

‎spring-boot-project/spring-boot-docs/pom.xml

+5
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@
135135
<artifactId>jackson-datatype-joda</artifactId>
136136
<optional>true</optional>
137137
</dependency>
138+
<dependency>
139+
<groupId>com.fasterxml.jackson.dataformat</groupId>
140+
<artifactId>jackson-dataformat-cbor</artifactId>
141+
<optional>true</optional>
142+
</dependency>
138143
<dependency>
139144
<groupId>com.fasterxml.jackson.dataformat</groupId>
140145
<artifactId>jackson-dataformat-xml</artifactId>

‎spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc

+16
Original file line numberDiff line numberDiff line change
@@ -3483,6 +3483,22 @@ The following code shows a typical `@Controller`:
34833483
}
34843484
----
34853485

3486+
[[boot-features-rsocket-strategies-auto-configuration]]
3487+
=== RSocket Strategies Auto-configuration
3488+
Spring Boot auto-configures an `RSocketStrategies` bean that provides all the required
3489+
infrastructure for encoding and decoding RSocket payloads. By default, the
3490+
auto-configuration will try to configure the following (in order):
3491+
3492+
1. https://cbor.io/[CBOR] codecs with Jackson
3493+
2. JSON codecs with Jackson
3494+
3495+
The `spring-boot-starter-rsocket` Starter provides both dependencies.
3496+
3497+
Developers can customize the `RSocketStrategies` component by creating beans that
3498+
implement the `RSocketStrategiesCustomizer` interface. Note that their `@Order` is
3499+
important, as it determines the order of codecs.
3500+
3501+
34863502
[[boot-features-rsocket-server-auto-configuration]]
34873503
=== RSocket server Auto-configuration
34883504
Spring Boot provides auto-configuration for RSocket servers. The required dependencies

‎spring-boot-project/spring-boot-starters/spring-boot-starter-rsocket/pom.xml

+4
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,9 @@
5454
<groupId>org.springframework.boot</groupId>
5555
<artifactId>spring-boot-starter-json</artifactId>
5656
</dependency>
57+
<dependency>
58+
<groupId>com.fasterxml.jackson.dataformat</groupId>
59+
<artifactId>jackson-dataformat-cbor</artifactId>
60+
</dependency>
5761
</dependencies>
5862
</project>

0 commit comments

Comments
 (0)
Please sign in to comment.