Polish + minor refactoring of SSE reader and writer

Instead of accepting List<Encoder|Decoder> and then look for the first
to support JSON, always expect a single JSON [Encoder|Decoder] and use
that unconditionally.

When writing use the nested ResolvableType instead of the Class of the
actual value which should better support generics.

Remove the SSE hint and pass "text/event-stream" as the media type
instead to serve as a hint. We are expecting a JSON encoder and using
it unconditionally in any case so this should be good enough.
This commit is contained in:
Rossen Stoyanchev
2017-03-21 17:32:14 -04:00
parent d0e0b6c8c9
commit a999f40daa
9 changed files with 155 additions and 198 deletions

View File

@@ -21,7 +21,6 @@ import java.util.Collections;
import org.junit.Test;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import org.springframework.core.ResolvableType;
@@ -39,8 +38,8 @@ import static org.junit.Assert.assertTrue;
*/
public class ServerSentEventHttpMessageReaderTests extends AbstractDataBufferAllocatingTestCase {
private ServerSentEventHttpMessageReader messageReader = new ServerSentEventHttpMessageReader(
Collections.singletonList(new Jackson2JsonDecoder()));
private ServerSentEventHttpMessageReader messageReader =
new ServerSentEventHttpMessageReader(new Jackson2JsonDecoder());
@Test
public void cantRead() {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,14 +18,15 @@ package org.springframework.http.codec;
import java.time.Duration;
import java.util.Collections;
import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import org.springframework.core.ResolvableType;
import org.springframework.core.io.buffer.AbstractDataBufferAllocatingTestCase;
import org.springframework.http.MediaType;
import org.springframework.http.codec.json.Jackson2JsonEncoder;
@@ -34,49 +35,45 @@ import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.springframework.core.ResolvableType.forClass;
/**
* Unit tests for {@link ServerSentEventHttpMessageWriter}.
* @author Sebastien Deleuze
* @author Rossen Stoyanchev
*/
public class ServerSentEventHttpMessageWriterTests extends AbstractDataBufferAllocatingTestCase {
private ServerSentEventHttpMessageWriter messageWriter = new ServerSentEventHttpMessageWriter(
Collections.singletonList(new Jackson2JsonEncoder()));
public static final Map<String, Object> HINTS = Collections.emptyMap();
private ServerSentEventHttpMessageWriter messageWriter =
new ServerSentEventHttpMessageWriter(new Jackson2JsonEncoder());
@Test
public void cantRead() {
assertFalse(messageWriter.canWrite(ResolvableType.forClass(Object.class),
new MediaType("foo", "bar")));
public void canWrite() {
assertTrue(this.messageWriter.canWrite(forClass(Object.class), null));
assertTrue(this.messageWriter.canWrite(null, MediaType.TEXT_EVENT_STREAM));
assertTrue(this.messageWriter.canWrite(forClass(ServerSentEvent.class), new MediaType("foo", "bar")));
}
@Test
public void canRead() {
assertTrue(messageWriter.canWrite(ResolvableType.forClass(Object.class), null));
assertTrue(messageWriter.canWrite(ResolvableType.forClass(Object.class),
new MediaType("text", "event-stream")));
assertTrue(messageWriter.canWrite(ResolvableType.forClass(ServerSentEvent.class),
new MediaType("bar", "bar")));
public void canNotWrite() {
assertFalse(this.messageWriter.canWrite(forClass(Object.class), new MediaType("foo", "bar")));
}
@Test
public void writeServerSentEvent() {
ServerSentEvent<String> event = ServerSentEvent.<String>builder().
data("bar").id("c42").event("foo").comment("bla\nbla bla\nbla bla bla")
.retry(Duration.ofMillis(123L)).build();
Mono<ServerSentEvent<String>> source = Mono.just(event);
ServerSentEvent<?> event = ServerSentEvent.builder().data("bar").id("c42").event("foo")
.comment("bla\nbla bla\nbla bla bla").retry(Duration.ofMillis(123L)).build();
Mono<ServerSentEvent> source = Mono.just(event);
MockServerHttpResponse outputMessage = new MockServerHttpResponse();
messageWriter.write(source, ResolvableType.forClass(ServerSentEvent.class),
new MediaType("text", "event-stream"), outputMessage, Collections.emptyMap()).block(Duration.ofMillis(5000));
testWrite(source, outputMessage, ServerSentEvent.class);
StepVerifier.create(outputMessage.getBodyAsString())
.expectNext("id:c42\n" +
"event:foo\n" +
"retry:123\n" +
":bla\n" +
":bla bla\n" +
":bla bla bla\n" +
"data:bar\n\n")
.expectNext("id:c42\nevent:foo\nretry:123\n:bla\n:bla bla\n:bla bla bla\ndata:bar\n\n")
.expectComplete()
.verify();
}
@@ -85,8 +82,7 @@ public class ServerSentEventHttpMessageWriterTests extends AbstractDataBufferAll
public void writeString() {
Flux<String> source = Flux.just("foo", "bar");
MockServerHttpResponse outputMessage = new MockServerHttpResponse();
messageWriter.write(source, ResolvableType.forClass(String.class),
new MediaType("text", "event-stream"), outputMessage, Collections.emptyMap()).block(Duration.ofMillis(5000));
testWrite(source, outputMessage, String.class);
StepVerifier.create(outputMessage.getBodyAsString())
.expectNext("data:foo\n\ndata:bar\n\n")
@@ -98,25 +94,19 @@ public class ServerSentEventHttpMessageWriterTests extends AbstractDataBufferAll
public void writeMultiLineString() {
Flux<String> source = Flux.just("foo\nbar", "foo\nbaz");
MockServerHttpResponse outputMessage = new MockServerHttpResponse();
messageWriter.write(source, ResolvableType.forClass(String.class),
new MediaType("text", "event-stream"), outputMessage, Collections.emptyMap()).block(Duration.ofMillis(5000));
testWrite(source, outputMessage, String.class);
StepVerifier.create(outputMessage.getBodyAsString())
.expectNext("data:foo\n" +
"data:bar\n\n" +
"data:foo\n" +
"data:baz\n\n")
.expectNext("data:foo\ndata:bar\n\ndata:foo\ndata:baz\n\n")
.expectComplete()
.verify();
}
@Test
public void writePojo() {
Flux<Pojo> source = Flux.just(new Pojo("foofoo", "barbar"),
new Pojo("foofoofoo", "barbarbar"));
Flux<Pojo> source = Flux.just(new Pojo("foofoo", "barbar"), new Pojo("foofoofoo", "barbarbar"));
MockServerHttpResponse outputMessage = new MockServerHttpResponse();
messageWriter.write(source, ResolvableType.forClass(Pojo.class),
MediaType.TEXT_EVENT_STREAM, outputMessage, Collections.emptyMap()).block(Duration.ofMillis(5000));
testWrite(source, outputMessage, Pojo.class);
StepVerifier.create(outputMessage.getBodyAsString())
.expectNext("data:{\"foo\":\"foofoo\",\"bar\":\"barbar\"}\n\n" +
@@ -127,15 +117,13 @@ public class ServerSentEventHttpMessageWriterTests extends AbstractDataBufferAll
@Test // SPR-14899
public void writePojoWithPrettyPrint() {
ObjectMapper mapper = Jackson2ObjectMapperBuilder.json().indentOutput(true).build();
this.messageWriter = new ServerSentEventHttpMessageWriter(
Collections.singletonList(new Jackson2JsonEncoder(mapper)));
Flux<Pojo> source = Flux.just(new Pojo("foofoo", "barbar"),
new Pojo("foofoofoo", "barbarbar"));
ObjectMapper mapper = Jackson2ObjectMapperBuilder.json().indentOutput(true).build();
this.messageWriter = new ServerSentEventHttpMessageWriter(new Jackson2JsonEncoder(mapper));
Flux<Pojo> source = Flux.just(new Pojo("foofoo", "barbar"), new Pojo("foofoofoo", "barbarbar"));
MockServerHttpResponse outputMessage = new MockServerHttpResponse();
messageWriter.write(source, ResolvableType.forClass(Pojo.class),
MediaType.TEXT_EVENT_STREAM, outputMessage, Collections.emptyMap()).block(Duration.ofMillis(5000));
testWrite(source, outputMessage, Pojo.class);
StepVerifier.create(outputMessage.getBodyAsString())
.expectNext("data:{\n" +
@@ -148,4 +136,9 @@ public class ServerSentEventHttpMessageWriterTests extends AbstractDataBufferAll
.verify();
}
private <T> void testWrite(Publisher<T> source, MockServerHttpResponse outputMessage, Class<T> clazz) {
this.messageWriter.write(source, forClass(clazz),
MediaType.TEXT_EVENT_STREAM, outputMessage, HINTS).block(Duration.ofMillis(5000));
}
}