Browse Source

Reactor StringEncoder into CharSequenceEncoder

This commit refactors the StringEncoder to a CharSequenceEncoder, in
order to support StringBuilders, Groovy GStrings, etc.

Issue: https://github.com/spring-projects/spring-reactive/issues/120
pull/1112/merge
Arjen Poutsma 9 years ago committed by Rossen Stoyanchev
parent
commit
b0d7625e3e
  1. 22
      spring-core/src/main/java/org/springframework/core/codec/CharSequenceEncoder.java
  2. 2
      spring-core/src/main/java/org/springframework/core/codec/StringDecoder.java
  3. 38
      spring-core/src/test/java/org/springframework/core/codec/CharSequenceEncoderTests.java
  4. 4
      spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfiguration.java
  5. 5
      spring-web-reactive/src/test/java/org/springframework/web/reactive/DispatcherHandlerErrorTests.java
  6. 17
      spring-web-reactive/src/test/java/org/springframework/web/reactive/config/WebReactiveConfigurationTests.java
  7. 5
      spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageWriterResultHandlerTests.java
  8. 4
      spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandlerTests.java
  9. 4
      spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseEntityResultHandlerTests.java
  10. 12
      spring-web-reactive/src/test/java/org/springframework/web/reactive/result/view/HttpMessageWriterViewTests.java
  11. 6
      spring-web/src/main/java/org/springframework/web/client/reactive/WebClient.java

22
spring-core/src/main/java/org/springframework/core/codec/StringEncoder.java → spring-core/src/main/java/org/springframework/core/codec/CharSequenceEncoder.java

@ -16,6 +16,8 @@ @@ -16,6 +16,8 @@
package org.springframework.core.codec;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
@ -28,18 +30,19 @@ import org.springframework.core.io.buffer.DataBufferFactory; @@ -28,18 +30,19 @@ import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.util.MimeType;
/**
* Encode from a String stream to a bytes stream.
* Encode from a CharSequence stream to a bytes stream.
*
* @author Sebastien Deleuze
* @author Arjen Poutsma
* @since 5.0
* @see StringDecoder
*/
public class StringEncoder extends AbstractEncoder<String> {
public class CharSequenceEncoder extends AbstractEncoder<CharSequence> {
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
public StringEncoder() {
public CharSequenceEncoder() {
super(new MimeType("text", "plain", DEFAULT_CHARSET));
}
@ -47,11 +50,11 @@ public class StringEncoder extends AbstractEncoder<String> { @@ -47,11 +50,11 @@ public class StringEncoder extends AbstractEncoder<String> {
@Override
public boolean canEncode(ResolvableType elementType, MimeType mimeType, Object... hints) {
Class<?> clazz = elementType.getRawClass();
return (super.canEncode(elementType, mimeType, hints) && String.class.equals(clazz));
return (super.canEncode(elementType, mimeType, hints) && CharSequence.class.isAssignableFrom(clazz));
}
@Override
public Flux<DataBuffer> encode(Publisher<? extends String> inputStream,
public Flux<DataBuffer> encode(Publisher<? extends CharSequence> inputStream,
DataBufferFactory bufferFactory, ResolvableType elementType,
MimeType mimeType, Object... hints) {
@ -62,11 +65,10 @@ public class StringEncoder extends AbstractEncoder<String> { @@ -62,11 +65,10 @@ public class StringEncoder extends AbstractEncoder<String> {
else {
charset = DEFAULT_CHARSET;
}
return Flux.from(inputStream).map(s -> {
byte[] bytes = s.getBytes(charset);
DataBuffer dataBuffer = bufferFactory.allocateBuffer(bytes.length);
dataBuffer.write(bytes);
return dataBuffer;
return Flux.from(inputStream).map(charSequence -> {
CharBuffer charBuffer = CharBuffer.wrap(charSequence);
ByteBuffer byteBuffer = charset.encode(charBuffer);
return bufferFactory.wrap(byteBuffer);
});
}

2
spring-core/src/main/java/org/springframework/core/codec/StringDecoder.java

@ -45,7 +45,7 @@ import org.springframework.util.MimeTypeUtils; @@ -45,7 +45,7 @@ import org.springframework.util.MimeTypeUtils;
* @author Arjen Poutsma
* @author Mark Paluch
* @since 5.0
* @see StringEncoder
* @see CharSequenceEncoder
*/
public class StringDecoder extends AbstractDecoder<String> {

38
spring-core/src/test/java/org/springframework/core/codec/StringEncoderTests.java → spring-core/src/test/java/org/springframework/core/codec/CharSequenceEncoderTests.java

@ -27,6 +27,7 @@ import reactor.test.TestSubscriber; @@ -27,6 +27,7 @@ import reactor.test.TestSubscriber;
import org.springframework.core.ResolvableType;
import org.springframework.core.io.buffer.AbstractDataBufferAllocatingTestCase;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.support.DataBufferUtils;
import org.springframework.util.MimeTypeUtils;
@ -37,35 +38,46 @@ import static org.junit.Assert.assertTrue; @@ -37,35 +38,46 @@ import static org.junit.Assert.assertTrue;
* @author Sebastien Deleuze
*/
@RunWith(Parameterized.class)
public class StringEncoderTests extends AbstractDataBufferAllocatingTestCase {
public class CharSequenceEncoderTests extends AbstractDataBufferAllocatingTestCase {
private StringEncoder encoder;
private CharSequenceEncoder encoder;
@Before
public void createEncoder() {
this.encoder = new StringEncoder();
this.encoder = new CharSequenceEncoder();
}
@Test
public void canWrite() {
assertTrue(this.encoder.canEncode(ResolvableType.forClass(String.class), MimeTypeUtils.TEXT_PLAIN));
assertTrue(this.encoder.canEncode(ResolvableType.forClass(StringBuilder.class), MimeTypeUtils.TEXT_PLAIN));
assertTrue(this.encoder.canEncode(ResolvableType.forClass(StringBuffer.class), MimeTypeUtils.TEXT_PLAIN));
assertFalse(this.encoder.canEncode(ResolvableType.forClass(Integer.class), MimeTypeUtils.TEXT_PLAIN));
assertFalse(this.encoder.canEncode(ResolvableType.forClass(String.class), MimeTypeUtils.APPLICATION_JSON));
}
@Test
public void write() throws InterruptedException {
Flux<String> output = Flux.from(
this.encoder.encode(Flux.just("foo"), this.bufferFactory, null, null))
.map(chunk -> {
byte[] b = new byte[chunk.readableByteCount()];
chunk.read(b);
DataBufferUtils.release(chunk);
return new String(b, StandardCharsets.UTF_8);
});
public void writeString() throws InterruptedException {
Flux<String> stringFlux = Flux.just("foo");
Flux<DataBuffer> output = Flux.from(
this.encoder.encode(stringFlux, this.bufferFactory, null, null));
TestSubscriber
.subscribe(output)
.assertValues("foo");
.assertNoError()
.assertComplete()
.assertValuesWith(stringConsumer("foo"));
}
@Test
public void writeStringBuilder() throws InterruptedException {
Flux<StringBuilder> stringBuilderFlux = Flux.just(new StringBuilder("foo"));
Flux<DataBuffer> output = Flux.from(
this.encoder.encode(stringBuilderFlux, this.bufferFactory, null, null));
TestSubscriber
.subscribe(output)
.assertNoError()
.assertComplete()
.assertValuesWith(stringConsumer("foo"));
}
}

4
spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfiguration.java

@ -29,10 +29,10 @@ import org.springframework.context.annotation.Bean; @@ -29,10 +29,10 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.codec.ByteBufferDecoder;
import org.springframework.core.codec.ByteBufferEncoder;
import org.springframework.core.codec.CharSequenceEncoder;
import org.springframework.core.codec.Encoder;
import org.springframework.core.codec.ResourceDecoder;
import org.springframework.core.codec.StringDecoder;
import org.springframework.core.codec.StringEncoder;
import org.springframework.core.convert.converter.Converter;
import org.springframework.format.Formatter;
import org.springframework.format.FormatterRegistry;
@ -368,7 +368,7 @@ public class WebReactiveConfiguration implements ApplicationContextAware { @@ -368,7 +368,7 @@ public class WebReactiveConfiguration implements ApplicationContextAware {
protected final void addDefaultHttpMessageWriters(List<HttpMessageWriter<?>> writers) {
List<Encoder<?>> sseDataEncoders = new ArrayList<>();
writers.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder()));
writers.add(new EncoderHttpMessageWriter<>(new StringEncoder()));
writers.add(new EncoderHttpMessageWriter<>(new CharSequenceEncoder()));
writers.add(new ResourceHttpMessageWriter());
if (jaxb2Present) {
writers.add(new EncoderHttpMessageWriter<>(new Jaxb2Encoder()));

5
spring-web-reactive/src/test/java/org/springframework/web/reactive/DispatcherHandlerErrorTests.java

@ -29,7 +29,7 @@ import reactor.test.TestSubscriber; @@ -29,7 +29,7 @@ import reactor.test.TestSubscriber;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.codec.StringEncoder;
import org.springframework.core.codec.CharSequenceEncoder;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpMethod;
@ -61,6 +61,7 @@ import static org.junit.Assert.assertEquals; @@ -61,6 +61,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
/**
* Test the effect of exceptions at different stages of request processing by
* checking the error signals on the completion publisher.
@ -197,7 +198,7 @@ public class DispatcherHandlerErrorTests { @@ -197,7 +198,7 @@ public class DispatcherHandlerErrorTests {
@Bean
public ResponseBodyResultHandler resultHandler() {
return new ResponseBodyResultHandler(
Collections.singletonList(new EncoderHttpMessageWriter<>(new StringEncoder())),
Collections.singletonList(new EncoderHttpMessageWriter<>(new CharSequenceEncoder())),
new HeaderContentTypeResolver());
}

17
spring-web-reactive/src/test/java/org/springframework/web/reactive/config/WebReactiveConfigurationTests.java

@ -13,6 +13,7 @@ @@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.reactive.config;
import java.net.URI;
@ -34,8 +35,8 @@ import org.springframework.context.annotation.Bean; @@ -34,8 +35,8 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.ResolvableType;
import org.springframework.core.codec.CharSequenceEncoder;
import org.springframework.core.codec.StringDecoder;
import org.springframework.core.codec.StringEncoder;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpMethod;
@ -68,16 +69,8 @@ import org.springframework.web.server.ServerWebExchange; @@ -68,16 +69,8 @@ import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.adapter.DefaultServerWebExchange;
import org.springframework.web.server.session.MockWebSessionManager;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM;
import static org.springframework.http.MediaType.APPLICATION_XML;
import static org.springframework.http.MediaType.IMAGE_PNG;
import static org.springframework.http.MediaType.TEXT_PLAIN;
import static org.junit.Assert.*;
import static org.springframework.http.MediaType.*;
/**
* Unit tests for {@link WebReactiveConfiguration}.
@ -307,7 +300,7 @@ public class WebReactiveConfigurationTests { @@ -307,7 +300,7 @@ public class WebReactiveConfigurationTests {
@Override
protected void configureMessageWriters(List<HttpMessageWriter<?>> messageWriters) {
messageWriters.add(new EncoderHttpMessageWriter<>(new StringEncoder()));
messageWriters.add(new EncoderHttpMessageWriter<>(new CharSequenceEncoder()));
}
@Override

5
spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageWriterResultHandlerTests.java

@ -30,7 +30,6 @@ import java.util.List; @@ -30,7 +30,6 @@ import java.util.List;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeName;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@ -40,7 +39,7 @@ import rx.Observable; @@ -40,7 +39,7 @@ import rx.Observable;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.core.codec.ByteBufferEncoder;
import org.springframework.core.codec.StringEncoder;
import org.springframework.core.codec.CharSequenceEncoder;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.buffer.support.DataBufferTestUtils;
@ -176,7 +175,7 @@ public class MessageWriterResultHandlerTests { @@ -176,7 +175,7 @@ public class MessageWriterResultHandlerTests {
if (ObjectUtils.isEmpty(writers)) {
writerList = new ArrayList<>();
writerList.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder()));
writerList.add(new EncoderHttpMessageWriter<>(new StringEncoder()));
writerList.add(new EncoderHttpMessageWriter<>(new CharSequenceEncoder()));
writerList.add(new ResourceHttpMessageWriter());
writerList.add(new EncoderHttpMessageWriter<>(new Jaxb2Encoder()));
writerList.add(new EncoderHttpMessageWriter<>(new JacksonJsonEncoder()));

4
spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandlerTests.java

@ -26,7 +26,7 @@ import org.junit.Test; @@ -26,7 +26,7 @@ import org.junit.Test;
import reactor.core.publisher.Mono;
import org.springframework.core.codec.ByteBufferEncoder;
import org.springframework.core.codec.StringEncoder;
import org.springframework.core.codec.CharSequenceEncoder;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.codec.json.JacksonJsonEncoder;
@ -86,7 +86,7 @@ public class ResponseBodyResultHandlerTests { @@ -86,7 +86,7 @@ public class ResponseBodyResultHandlerTests {
if (ObjectUtils.isEmpty(writers)) {
writerList = new ArrayList<>();
writerList.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder()));
writerList.add(new EncoderHttpMessageWriter<>(new StringEncoder()));
writerList.add(new EncoderHttpMessageWriter<>(new CharSequenceEncoder()));
writerList.add(new ResourceHttpMessageWriter());
writerList.add(new EncoderHttpMessageWriter<>(new Jaxb2Encoder()));
writerList.add(new EncoderHttpMessageWriter<>(new JacksonJsonEncoder()));

4
spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseEntityResultHandlerTests.java

@ -33,7 +33,7 @@ import rx.Single; @@ -33,7 +33,7 @@ import rx.Single;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.core.codec.ByteBufferEncoder;
import org.springframework.core.codec.StringEncoder;
import org.springframework.core.codec.CharSequenceEncoder;
import org.springframework.core.io.buffer.support.DataBufferTestUtils;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
@ -91,7 +91,7 @@ public class ResponseEntityResultHandlerTests { @@ -91,7 +91,7 @@ public class ResponseEntityResultHandlerTests {
if (ObjectUtils.isEmpty(writers)) {
writerList = new ArrayList<>();
writerList.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder()));
writerList.add(new EncoderHttpMessageWriter<>(new StringEncoder()));
writerList.add(new EncoderHttpMessageWriter<>(new CharSequenceEncoder()));
writerList.add(new ResourceHttpMessageWriter());
writerList.add(new EncoderHttpMessageWriter<>(new Jaxb2Encoder()));
writerList.add(new EncoderHttpMessageWriter<>(new JacksonJsonEncoder()));

12
spring-web-reactive/src/test/java/org/springframework/web/reactive/result/view/HttpMessageWriterViewTests.java

@ -13,11 +13,10 @@ @@ -13,11 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.reactive.result.view;
package org.springframework.web.reactive.result.view;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
@ -32,7 +31,7 @@ import org.junit.Test; @@ -32,7 +31,7 @@ import org.junit.Test;
import reactor.test.TestSubscriber;
import org.springframework.core.MethodParameter;
import org.springframework.core.codec.StringEncoder;
import org.springframework.core.codec.CharSequenceEncoder;
import org.springframework.core.io.buffer.support.DataBufferTestUtils;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
@ -51,10 +50,7 @@ import org.springframework.web.server.session.DefaultWebSessionManager; @@ -51,10 +50,7 @@ import org.springframework.web.server.session.DefaultWebSessionManager;
import org.springframework.web.server.session.WebSessionManager;
import static junit.framework.TestCase.assertTrue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import static org.junit.Assert.*;
/**
@ -123,7 +119,7 @@ public class HttpMessageWriterViewTests { @@ -123,7 +119,7 @@ public class HttpMessageWriterViewTests {
@Test
public void extractObjectMultipleMatchesNotSupported() throws Exception {
HttpMessageWriterView view = new HttpMessageWriterView(new StringEncoder());
HttpMessageWriterView view = new HttpMessageWriterView(new CharSequenceEncoder());
view.setModelKeys(new HashSet<>(Arrays.asList("foo1", "foo2")));
this.model.addAttribute("foo1", "bar1");
this.model.addAttribute("foo2", "bar2");

6
spring-web/src/main/java/org/springframework/web/client/reactive/WebClient.java

@ -30,9 +30,9 @@ import reactor.core.publisher.Mono; @@ -30,9 +30,9 @@ import reactor.core.publisher.Mono;
import org.springframework.core.ResolvableType;
import org.springframework.core.codec.ByteBufferDecoder;
import org.springframework.core.codec.ByteBufferEncoder;
import org.springframework.core.codec.CharSequenceEncoder;
import org.springframework.core.codec.ResourceDecoder;
import org.springframework.core.codec.StringDecoder;
import org.springframework.core.codec.StringEncoder;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.reactive.ClientHttpConnector;
@ -105,7 +105,7 @@ public final class WebClient { @@ -105,7 +105,7 @@ public final class WebClient {
* Register by default the following Encoders and Decoders:
* <ul>
* <li>{@link ByteBufferEncoder} / {@link ByteBufferDecoder}</li>
* <li>{@link StringEncoder} / {@link StringDecoder}</li>
* <li>{@link CharSequenceEncoder} / {@link StringDecoder}</li>
* <li>{@link Jaxb2Encoder} / {@link Jaxb2Decoder}</li>
* <li>{@link JacksonJsonEncoder} / {@link JacksonJsonDecoder}</li>
* </ul>
@ -138,7 +138,7 @@ public final class WebClient { @@ -138,7 +138,7 @@ public final class WebClient {
*/
protected final void addDefaultHttpMessageWriters(List<HttpMessageWriter<?>> messageWriters) {
messageWriters.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder()));
messageWriters.add(new EncoderHttpMessageWriter<>(new StringEncoder()));
messageWriters.add(new EncoderHttpMessageWriter<>(new CharSequenceEncoder()));
messageWriters.add(new ResourceHttpMessageWriter());
if (jaxb2Present) {
messageWriters.add(new EncoderHttpMessageWriter<>(new Jaxb2Encoder()));

Loading…
Cancel
Save