Polish Encoder and Decoder

This commit is contained in:
Rossen Stoyanchev 2016-06-08 15:06:27 -04:00
parent a8e5e40d97
commit 4e3c439593
18 changed files with 96 additions and 85 deletions

View File

@ -26,35 +26,42 @@ import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.util.MimeType;
/**
* Decode a stream of bytes to a stream of type {@code T}.
* Strategy for decoding a {@link DataBuffer} input stream into an output stream
* of elements of type {@code <T>}.
*
* @author Sebastien Deleuze
* @see Encoder
* @author Rossen Stoyanchev
* @param <T> the type of elements in the output stream
*/
public interface Decoder<T> {
/**
* Whether the decoder supports the given Java and mime type.
* @param type the stream element type to process.
* @param mimeType the mime type to process.
* @param hints Additional information about how to do decode, optional.
* @return {@code true} if can process; {@code false} otherwise
* Whether the decoder supports the given target element type and the MIME
* type of the source stream.
*
* @param elementType the target element type for the output stream
* @param mimeType the mime type associated with the stream to decode
* @param hints additional information about how to do decode, optional
* @return {@code true} if supported, {@code false} otherwise
*/
boolean canDecode(ResolvableType type, MimeType mimeType, Object... hints);
boolean canDecode(ResolvableType elementType, MimeType mimeType, Object... hints);
/**
* Decode an input {@link DataBuffer} stream to an output stream of {@code T}.
* @param inputStream the input stream to process.
* @param type the stream element type to process.
* @param mimeType the mime type to process.
* @param hints Additional information about how to do decode, optional.
* @return the output stream
* Decode a {@link DataBuffer} input stream into a Flux of {@code T}.
*
* @param inputStream the {@code DataBuffer} input stream to decode
* @param elementType the expected type of elements in the output stream;
* this type must have been previously passed to the {@link #canDecode}
* method and it must have returned {@code true}.
* @param mimeType the MIME type associated with the input stream, optional
* @param hints additional information about how to do decode, optional
* @return the output stream with decoded elements
*/
Flux<T> decode(Publisher<DataBuffer> inputStream, ResolvableType type,
Flux<T> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType,
MimeType mimeType, Object... hints);
/**
* Return the list of mime types this decoder supports.
* Return the list of MIME types this decoder supports.
*/
List<MimeType> getSupportedMimeTypes();

View File

@ -27,34 +27,41 @@ import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.util.MimeType;
/**
* Encode a stream of Objects of type {@code T} into a stream of bytes.
* Strategy to encode a stream of Objects of type {@code <T>} into an output
* stream of bytes.
*
* @author Sebastien Deleuze
* @see Decoder
* @author Rossen Stoyanchev
* @param <T> the type of elements in the input stream
*/
public interface Encoder<T> {
/**
* Indicate whether the given type and mime type can be processed by this encoder.
* @param type the stream element type to process.
* @param mimeType the mime type to process.
* @param hints Additional information about how to do decode, optional.
* @return {@code true} if can process; {@code false} otherwise
* Whether the encoder supports the given source element type and the MIME
* type for the output stream.
*
* @param elementType the type of elements in the source stream
* @param mimeType the MIME type for the output stream
* @param hints additional information about how to do encode, optional
* @return {@code true} if supported, {@code false} otherwise
*/
boolean canEncode(ResolvableType type, MimeType mimeType, Object... hints);
boolean canEncode(ResolvableType elementType, MimeType mimeType, Object... hints);
/**
* Encode an input stream of {@code T} to an output {@link DataBuffer} stream.
* @param inputStream the input stream to process.
* @param dataBufferFactory a buffer factory used to create the output
* @param type the stream element type to process.
* @param mimeType the mime type to process.
* @param hints Additional information about how to do decode, optional.
* Encode a stream of Objects of type {@code T} into a {@link DataBuffer}
* output stream.
*
* @param inputStream the input stream of Objects to encode
* @param bufferFactory for creating output stream {@code DataBuffer}'s
* @param elementType the expected type of elements in the input stream;
* this type must have been previously passed to the {@link #canEncode}
* method and it must have returned {@code true}.
* @param mimeType the MIME type for the output stream
* @param hints additional information about how to do encode, optional
* @return the output stream
*/
Flux<DataBuffer> encode(Publisher<? extends T> inputStream,
DataBufferFactory dataBufferFactory, ResolvableType type,
MimeType mimeType, Object... hints);
Flux<DataBuffer> encode(Publisher<? extends T> inputStream, DataBufferFactory bufferFactory,
ResolvableType elementType, MimeType mimeType, Object... hints);
/**
* Return the list of mime types this encoder supports.

View File

@ -42,7 +42,7 @@ public abstract class AbstractDecoder<T> implements Decoder<T> {
}
@Override
public boolean canDecode(ResolvableType type, MimeType mimeType, Object... hints) {
public boolean canDecode(ResolvableType elementType, MimeType mimeType, Object... hints) {
if (mimeType == null) {
return true;
}

View File

@ -42,7 +42,7 @@ public abstract class AbstractEncoder<T> implements Encoder<T> {
}
@Override
public boolean canEncode(ResolvableType type, MimeType mimeType, Object... hints) {
public boolean canEncode(ResolvableType elementType, MimeType mimeType, Object... hints) {
if (mimeType == null) {
return true;
}

View File

@ -37,13 +37,13 @@ public abstract class AbstractSingleValueEncoder<T> extends AbstractEncoder<T> {
@Override
public final Flux<DataBuffer> encode(Publisher<? extends T> inputStream,
DataBufferFactory dataBufferFactory, ResolvableType type, MimeType mimeType,
DataBufferFactory bufferFactory, ResolvableType elementType, MimeType mimeType,
Object... hints) {
return Flux.from(inputStream).
take(1).
concatMap(t -> {
try {
return encode(t, dataBufferFactory, type, mimeType);
return encode(t, bufferFactory, elementType, mimeType);
}
catch (Exception ex) {
return Flux.error(ex);

View File

@ -40,13 +40,13 @@ public class ByteBufferDecoder extends AbstractDecoder<ByteBuffer> {
@Override
public boolean canDecode(ResolvableType type, MimeType mimeType, Object... hints) {
Class<?> clazz = type.getRawClass();
return (super.canDecode(type, mimeType, hints) && ByteBuffer.class.isAssignableFrom(clazz));
public boolean canDecode(ResolvableType elementType, MimeType mimeType, Object... hints) {
Class<?> clazz = elementType.getRawClass();
return (super.canDecode(elementType, mimeType, hints) && ByteBuffer.class.isAssignableFrom(clazz));
}
@Override
public Flux<ByteBuffer> decode(Publisher<DataBuffer> inputStream, ResolvableType type,
public Flux<ByteBuffer> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType,
MimeType mimeType, Object... hints) {
return Flux.from(inputStream).map((dataBuffer) -> {
ByteBuffer copy = ByteBuffer.allocate(dataBuffer.readableByteCount());

View File

@ -38,17 +38,17 @@ public class ByteBufferEncoder extends AbstractEncoder<ByteBuffer> {
@Override
public boolean canEncode(ResolvableType type, MimeType mimeType, Object... hints) {
Class<?> clazz = type.getRawClass();
return (super.canEncode(type, mimeType, hints) && ByteBuffer.class.isAssignableFrom(clazz));
public boolean canEncode(ResolvableType elementType, MimeType mimeType, Object... hints) {
Class<?> clazz = elementType.getRawClass();
return (super.canEncode(elementType, mimeType, hints) && ByteBuffer.class.isAssignableFrom(clazz));
}
@Override
public Flux<DataBuffer> encode(Publisher<? extends ByteBuffer> inputStream,
DataBufferFactory dataBufferFactory, ResolvableType type, MimeType mimeType,
DataBufferFactory bufferFactory, ResolvableType elementType, MimeType mimeType,
Object... hints) {
return Flux.from(inputStream).map(dataBufferFactory::wrap);
return Flux.from(inputStream).map(bufferFactory::wrap);
}
}

View File

@ -61,14 +61,14 @@ public class JacksonJsonDecoder extends AbstractDecoder<Object> {
}
@Override
public Flux<Object> decode(Publisher<DataBuffer> inputStream, ResolvableType type,
public Flux<Object> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType,
MimeType mimeType, Object... hints) {
ObjectReader reader = this.mapper.readerFor(type.getRawClass());
ObjectReader reader = this.mapper.readerFor(elementType.getRawClass());
Flux<DataBuffer> stream = Flux.from(inputStream);
if (this.preProcessor != null) {
stream = this.preProcessor.decode(inputStream, type, mimeType, hints);
stream = this.preProcessor.decode(inputStream, elementType, mimeType, hints);
}
return stream.map(dataBuffer -> {

View File

@ -64,24 +64,24 @@ public class JacksonJsonEncoder extends AbstractEncoder<Object> {
@Override
public Flux<DataBuffer> encode(Publisher<?> inputStream,
DataBufferFactory dataBufferFactory, ResolvableType type, MimeType mimeType,
DataBufferFactory bufferFactory, ResolvableType elementType, MimeType mimeType,
Object... hints) {
if (inputStream instanceof Mono) {
// single object
return Flux.from(inputStream)
.map(value -> serialize(value, dataBufferFactory));
.map(value -> serialize(value, bufferFactory));
}
else {
// array
Mono<DataBuffer> startArray =
Mono.just(dataBufferFactory.wrap(START_ARRAY_BUFFER));
Mono.just(bufferFactory.wrap(START_ARRAY_BUFFER));
Flux<DataBuffer> arraySeparators =
Mono.just(dataBufferFactory.wrap(SEPARATOR_BUFFER)).repeat();
Mono.just(bufferFactory.wrap(SEPARATOR_BUFFER)).repeat();
Mono<DataBuffer> endArray =
Mono.just(dataBufferFactory.wrap(END_ARRAY_BUFFER));
Mono.just(bufferFactory.wrap(END_ARRAY_BUFFER));
Flux<DataBuffer> serializedObjects = Flux.from(inputStream)
.map(value -> serialize(value, dataBufferFactory));
.map(value -> serialize(value, bufferFactory));
Flux<DataBuffer> array = Flux.zip(serializedObjects, arraySeparators)
.flatMap(tuple -> Flux.just(tuple.getT1(), tuple.getT2()));

View File

@ -69,9 +69,9 @@ public class Jaxb2Decoder extends AbstractDecoder<Object> {
}
@Override
public boolean canDecode(ResolvableType type, MimeType mimeType, Object... hints) {
if (super.canDecode(type, mimeType, hints)) {
Class<?> outputClass = type.getRawClass();
public boolean canDecode(ResolvableType elementType, MimeType mimeType, Object... hints) {
if (super.canDecode(elementType, mimeType, hints)) {
Class<?> outputClass = elementType.getRawClass();
return outputClass.isAnnotationPresent(XmlRootElement.class) ||
outputClass.isAnnotationPresent(XmlType.class);
}
@ -81,9 +81,9 @@ public class Jaxb2Decoder extends AbstractDecoder<Object> {
}
@Override
public Flux<Object> decode(Publisher<DataBuffer> inputStream, ResolvableType type,
public Flux<Object> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType,
MimeType mimeType, Object... hints) {
Class<?> outputClass = type.getRawClass();
Class<?> outputClass = elementType.getRawClass();
Flux<XMLEvent> xmlEventFlux =
this.xmlEventDecoder.decode(inputStream, null, mimeType);

View File

@ -48,9 +48,9 @@ public class Jaxb2Encoder extends AbstractSingleValueEncoder<Object> {
}
@Override
public boolean canEncode(ResolvableType type, MimeType mimeType, Object... hints) {
if (super.canEncode(type, mimeType, hints)) {
Class<?> outputClass = type.getRawClass();
public boolean canEncode(ResolvableType elementType, MimeType mimeType, Object... hints) {
if (super.canEncode(elementType, mimeType, hints)) {
Class<?> outputClass = elementType.getRawClass();
return outputClass.isAnnotationPresent(XmlRootElement.class) ||
outputClass.isAnnotationPresent(XmlType.class);
}

View File

@ -93,7 +93,7 @@ public class JsonObjectDecoder extends AbstractDecoder<DataBuffer> {
}
@Override
public Flux<DataBuffer> decode(Publisher<DataBuffer> inputStream, ResolvableType type,
public Flux<DataBuffer> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType,
MimeType mimeType, Object... hints) {
return Flux.from(inputStream)

View File

@ -43,17 +43,17 @@ public class ResourceDecoder extends AbstractDecoder<Resource> {
}
@Override
public boolean canDecode(ResolvableType type, MimeType mimeType, Object... hints) {
Class<?> clazz = type.getRawClass();
public boolean canDecode(ResolvableType elementType, MimeType mimeType, Object... hints) {
Class<?> clazz = elementType.getRawClass();
return (InputStreamResource.class.equals(clazz) ||
clazz.isAssignableFrom(ByteArrayResource.class)) &&
super.canDecode(type, mimeType, hints);
super.canDecode(elementType, mimeType, hints);
}
@Override
public Flux<Resource> decode(Publisher<DataBuffer> inputStream, ResolvableType type,
public Flux<Resource> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType,
MimeType mimeType, Object... hints) {
Class<?> clazz = type.getRawClass();
Class<?> clazz = elementType.getRawClass();
Mono<byte[]> byteArray = Flux.from(inputStream).
reduce(DataBuffer::write).

View File

@ -52,9 +52,9 @@ public class ResourceEncoder extends AbstractSingleValueEncoder<Resource> {
}
@Override
public boolean canEncode(ResolvableType type, MimeType mimeType, Object... hints) {
Class<?> clazz = type.getRawClass();
return (super.canEncode(type, mimeType, hints) &&
public boolean canEncode(ResolvableType elementType, MimeType mimeType, Object... hints) {
Class<?> clazz = elementType.getRawClass();
return (super.canEncode(elementType, mimeType, hints) &&
Resource.class.isAssignableFrom(clazz));
}

View File

@ -70,13 +70,13 @@ public class StringDecoder extends AbstractDecoder<String> {
}
@Override
public boolean canDecode(ResolvableType type, MimeType mimeType, Object... hints) {
return super.canDecode(type, mimeType, hints) &&
String.class.equals(type.getRawClass());
public boolean canDecode(ResolvableType elementType, MimeType mimeType, Object... hints) {
return super.canDecode(elementType, mimeType, hints) &&
String.class.equals(elementType.getRawClass());
}
@Override
public Flux<String> decode(Publisher<DataBuffer> inputStream, ResolvableType type,
public Flux<String> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType,
MimeType mimeType, Object... hints) {
Flux<DataBuffer> inputFlux = Flux.from(inputStream);
if (this.splitOnNewline) {

View File

@ -43,14 +43,14 @@ public class StringEncoder extends AbstractEncoder<String> {
@Override
public boolean canEncode(ResolvableType type, MimeType mimeType, Object... hints) {
Class<?> clazz = type.getRawClass();
return (super.canEncode(type, mimeType, hints) && String.class.equals(clazz));
public boolean canEncode(ResolvableType elementType, MimeType mimeType, Object... hints) {
Class<?> clazz = elementType.getRawClass();
return (super.canEncode(elementType, mimeType, hints) && String.class.equals(clazz));
}
@Override
public Flux<DataBuffer> encode(Publisher<? extends String> inputStream,
DataBufferFactory dataBufferFactory, ResolvableType type, MimeType mimeType,
DataBufferFactory bufferFactory, ResolvableType elementType, MimeType mimeType,
Object... hints) {
Charset charset;
if (mimeType != null && mimeType.getCharSet() != null) {
@ -61,7 +61,7 @@ public class StringEncoder extends AbstractEncoder<String> {
}
return Flux.from(inputStream).map(s -> {
byte[] bytes = s.getBytes(charset);
DataBuffer dataBuffer = dataBufferFactory.allocateBuffer(bytes.length);
DataBuffer dataBuffer = bufferFactory.allocateBuffer(bytes.length);
dataBuffer.write(bytes);
return dataBuffer;
});

View File

@ -83,7 +83,7 @@ public class XmlEventDecoder extends AbstractDecoder<XMLEvent> {
}
@Override
public Flux<XMLEvent> decode(Publisher<DataBuffer> inputStream, ResolvableType type,
public Flux<XMLEvent> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType,
MimeType mimeType, Object... hints) {
Flux<DataBuffer> flux = Flux.from(inputStream);
if (useAalto && aaltoPresent) {

View File

@ -19,8 +19,6 @@ package org.springframework.web.reactive.result.method.annotation;
import java.util.List;
import java.util.stream.Collectors;
import javax.xml.crypto.Data;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@ -28,7 +26,6 @@ import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.MediaType;
import org.springframework.http.converter.reactive.HttpMessageConverter;
import org.springframework.ui.ModelMap;