MetadataExtractor refactoring
Remove RSocketStrategies argument from the contract to avoid having to pass them every time especially by application components, like an implementation of a Spring Security matcher. Decouple DefaultMetadataExtractor from RSocketStrategies in favor of a decoders property and an internal DataBufferFactory, which does not need to be the shared one as we're only wrapping ByteBufs.
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
package org.springframework.messaging.rsocket;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import io.netty.buffer.PooledByteBufAllocator;
|
||||
@@ -28,13 +29,15 @@ import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.BDDMockito;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.codec.CharSequenceEncoder;
|
||||
import org.springframework.core.codec.ByteArrayDecoder;
|
||||
import org.springframework.core.codec.StringDecoder;
|
||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.MimeType;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.springframework.messaging.rsocket.MetadataExtractor.COMPOSITE_METADATA;
|
||||
import static org.springframework.messaging.rsocket.MetadataExtractor.ROUTE_KEY;
|
||||
import static org.springframework.messaging.rsocket.MetadataExtractor.ROUTING;
|
||||
@@ -61,8 +64,6 @@ public class DefaultMetadataExtractorTests {
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.strategies = RSocketStrategies.builder()
|
||||
.decoder(StringDecoder.allMimeTypes())
|
||||
.encoder(CharSequenceEncoder.allMimeTypes())
|
||||
.dataBufferFactory(new LeakAwareNettyDataBufferFactory(PooledByteBufAllocator.DEFAULT))
|
||||
.build();
|
||||
|
||||
@@ -71,6 +72,7 @@ public class DefaultMetadataExtractorTests {
|
||||
BDDMockito.when(this.rsocket.fireAndForget(captor.capture())).thenReturn(Mono.empty());
|
||||
|
||||
this.extractor = new DefaultMetadataExtractor();
|
||||
this.extractor.setDecoders(Collections.singletonList(StringDecoder.allMimeTypes()));
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -82,7 +84,6 @@ public class DefaultMetadataExtractorTests {
|
||||
|
||||
@Test
|
||||
public void compositeMetadataWithDefaultSettings() {
|
||||
|
||||
requester(COMPOSITE_METADATA).route("toA")
|
||||
.metadata("text data", TEXT_PLAIN)
|
||||
.metadata("html data", TEXT_HTML)
|
||||
@@ -91,7 +92,7 @@ public class DefaultMetadataExtractorTests {
|
||||
.send().block();
|
||||
|
||||
Payload payload = this.captor.getValue();
|
||||
Map<String, Object> result = this.extractor.extract(payload, COMPOSITE_METADATA, this.strategies);
|
||||
Map<String, Object> result = this.extractor.extract(payload, COMPOSITE_METADATA);
|
||||
payload.release();
|
||||
|
||||
assertThat(result).hasSize(1).containsEntry(ROUTE_KEY, "toA");
|
||||
@@ -99,7 +100,6 @@ public class DefaultMetadataExtractorTests {
|
||||
|
||||
@Test
|
||||
public void compositeMetadataWithMimeTypeRegistrations() {
|
||||
|
||||
this.extractor.metadataToExtract(TEXT_PLAIN, String.class, "text-entry");
|
||||
this.extractor.metadataToExtract(TEXT_HTML, String.class, "html-entry");
|
||||
this.extractor.metadataToExtract(TEXT_XML, String.class, "xml-entry");
|
||||
@@ -113,7 +113,7 @@ public class DefaultMetadataExtractorTests {
|
||||
.block();
|
||||
|
||||
Payload payload = this.captor.getValue();
|
||||
Map<String, Object> result = this.extractor.extract(payload, COMPOSITE_METADATA, this.strategies);
|
||||
Map<String, Object> result = this.extractor.extract(payload, COMPOSITE_METADATA);
|
||||
payload.release();
|
||||
|
||||
assertThat(result).hasSize(4)
|
||||
@@ -125,10 +125,9 @@ public class DefaultMetadataExtractorTests {
|
||||
|
||||
@Test
|
||||
public void route() {
|
||||
|
||||
requester(ROUTING).route("toA").data("data").send().block();
|
||||
Payload payload = this.captor.getValue();
|
||||
Map<String, Object> result = this.extractor.extract(payload, ROUTING, this.strategies);
|
||||
Map<String, Object> result = this.extractor.extract(payload, ROUTING);
|
||||
payload.release();
|
||||
|
||||
assertThat(result).hasSize(1).containsEntry(ROUTE_KEY, "toA");
|
||||
@@ -136,12 +135,11 @@ public class DefaultMetadataExtractorTests {
|
||||
|
||||
@Test
|
||||
public void routeAsText() {
|
||||
|
||||
this.extractor.metadataToExtract(TEXT_PLAIN, String.class, ROUTE_KEY);
|
||||
|
||||
requester(TEXT_PLAIN).route("toA").data("data").send().block();
|
||||
Payload payload = this.captor.getValue();
|
||||
Map<String, Object> result = this.extractor.extract(payload, TEXT_PLAIN, this.strategies);
|
||||
Map<String, Object> result = this.extractor.extract(payload, TEXT_PLAIN);
|
||||
payload.release();
|
||||
|
||||
assertThat(result).hasSize(1).containsEntry(ROUTE_KEY, "toA");
|
||||
@@ -149,7 +147,6 @@ public class DefaultMetadataExtractorTests {
|
||||
|
||||
@Test
|
||||
public void routeWithCustomFormatting() {
|
||||
|
||||
this.extractor.metadataToExtract(TEXT_PLAIN, String.class, (text, result) -> {
|
||||
String[] items = text.split(":");
|
||||
Assert.isTrue(items.length == 2, "Expected two items");
|
||||
@@ -159,7 +156,7 @@ public class DefaultMetadataExtractorTests {
|
||||
|
||||
requester(TEXT_PLAIN).metadata("toA:text data", null).data("data").send().block();
|
||||
Payload payload = this.captor.getValue();
|
||||
Map<String, Object> result = this.extractor.extract(payload, TEXT_PLAIN, this.strategies);
|
||||
Map<String, Object> result = this.extractor.extract(payload, TEXT_PLAIN);
|
||||
payload.release();
|
||||
|
||||
assertThat(result).hasSize(2)
|
||||
@@ -167,6 +164,59 @@ public class DefaultMetadataExtractorTests {
|
||||
.containsEntry("entry1", "text data");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addMetadataToExtractBeforeDecoders() {
|
||||
DefaultMetadataExtractor extractor = new DefaultMetadataExtractor();
|
||||
extractor.metadataToExtract(TEXT_PLAIN, String.class, "key");
|
||||
extractor.setDecoders(Collections.singletonList(StringDecoder.allMimeTypes()));
|
||||
|
||||
requester(TEXT_PLAIN).metadata("meta entry", null).data("data").send().block();
|
||||
Payload payload = this.captor.getValue();
|
||||
Map<String, Object> result = extractor.extract(payload, TEXT_PLAIN);
|
||||
payload.release();
|
||||
|
||||
assertThat(result).hasSize(1).containsEntry("key", "meta entry");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noDecoderExceptionWhenSettingDecoders() {
|
||||
DefaultMetadataExtractor extractor = new DefaultMetadataExtractor();
|
||||
extractor.metadataToExtract(TEXT_PLAIN, String.class, "key");
|
||||
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> extractor.setDecoders(Collections.singletonList(new ByteArrayDecoder())))
|
||||
.withMessage("No decoder for MetadataProcessor mimeType=text/plain, targetType=java.lang.String");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noDecoderExceptionWhenRegisteringMetadataToExtract() {
|
||||
DefaultMetadataExtractor extractor = new DefaultMetadataExtractor();
|
||||
extractor.setDecoders(Collections.singletonList(new ByteArrayDecoder()));
|
||||
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> extractor.metadataToExtract(TEXT_PLAIN, String.class, "key"))
|
||||
.withMessage("No decoder for text/plain");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decodersNotSet() {
|
||||
DefaultMetadataExtractor extractor = new DefaultMetadataExtractor();
|
||||
extractor.metadataToExtract(TEXT_PLAIN, String.class, "key");
|
||||
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> {
|
||||
requester(TEXT_PLAIN).metadata("meta entry", null).data("data").send().block();
|
||||
Payload payload = this.captor.getValue();
|
||||
try {
|
||||
extractor.extract(payload, TEXT_PLAIN);
|
||||
}
|
||||
finally {
|
||||
payload.release();
|
||||
}
|
||||
})
|
||||
.withMessage("No decoder for MetadataProcessor mimeType=text/plain, targetType=java.lang.String");
|
||||
}
|
||||
|
||||
|
||||
private RSocketRequester requester(MimeType metadataMimeType) {
|
||||
return RSocketRequester.wrap(this.rsocket, TEXT_PLAIN, metadataMimeType, this.strategies);
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.messaging.rsocket;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.core.ReactiveAdapterRegistry;
|
||||
@@ -87,6 +89,39 @@ public class DefaultRSocketStrategiesTests {
|
||||
assertThat(strategies.reactiveAdapterRegistry()).isSameAs(registry);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void metadataExtractorInitializedWithDecoders() {
|
||||
DefaultMetadataExtractor extractor = new DefaultMetadataExtractor();
|
||||
|
||||
RSocketStrategies strategies = RSocketStrategies.builder()
|
||||
.decoders(decoders -> {
|
||||
decoders.clear();
|
||||
decoders.add(new ByteArrayDecoder());
|
||||
decoders.add(new ByteBufferDecoder());
|
||||
})
|
||||
.metadataExtractor(extractor)
|
||||
.build();
|
||||
|
||||
assertThat(((DefaultMetadataExtractor) strategies.metadataExtractor()).getDecoders()).hasSize(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void metadataExtractorWithExplicitlySetDecoders() {
|
||||
DefaultMetadataExtractor extractor = new DefaultMetadataExtractor();
|
||||
extractor.setDecoders(Collections.singletonList(StringDecoder.allMimeTypes()));
|
||||
|
||||
RSocketStrategies strategies = RSocketStrategies.builder()
|
||||
.decoders(decoders -> {
|
||||
decoders.clear();
|
||||
decoders.add(new ByteArrayDecoder());
|
||||
decoders.add(new ByteBufferDecoder());
|
||||
})
|
||||
.metadataExtractor(extractor)
|
||||
.build();
|
||||
|
||||
assertThat(((DefaultMetadataExtractor) strategies.metadataExtractor()).getDecoders()).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyConstructor() {
|
||||
RSocketStrategies strategies1 = RSocketStrategies.create();
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.messaging.rsocket.annotation.support;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -158,6 +159,31 @@ public class RSocketMessageHandlerTests {
|
||||
assertThat(strategies.reactiveAdapterRegistry()).isSameAs(handler.getReactiveAdapterRegistry());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void metadataExtractorInitializedWithDecoders() {
|
||||
DefaultMetadataExtractor extractor = new DefaultMetadataExtractor();
|
||||
|
||||
RSocketMessageHandler handler = new RSocketMessageHandler();
|
||||
handler.setDecoders(Arrays.asList(new ByteArrayDecoder(), new ByteBufferDecoder()));
|
||||
handler.setMetadataExtractor(extractor);
|
||||
handler.afterPropertiesSet();
|
||||
|
||||
assertThat(((DefaultMetadataExtractor) handler.getMetadataExtractor()).getDecoders()).hasSize(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void metadataExtractorWithExplicitlySetDecoders() {
|
||||
DefaultMetadataExtractor extractor = new DefaultMetadataExtractor();
|
||||
extractor.setDecoders(Collections.singletonList(StringDecoder.allMimeTypes()));
|
||||
|
||||
RSocketMessageHandler handler = new RSocketMessageHandler();
|
||||
handler.setDecoders(Arrays.asList(new ByteArrayDecoder(), new ByteBufferDecoder()));
|
||||
handler.setMetadataExtractor(extractor);
|
||||
handler.afterPropertiesSet();
|
||||
|
||||
assertThat(((DefaultMetadataExtractor) handler.getMetadataExtractor()).getDecoders()).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappings() {
|
||||
testMapping(new SimpleController(), "path");
|
||||
|
||||
Reference in New Issue
Block a user