Polish Encoder and Decoder
This commit is contained in:
parent
a8e5e40d97
commit
4e3c439593
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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 -> {
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue