Refactor codecs
This commit introduces the following changes: - MessageToByteEncoder/Decoder renamed to Encoder/Decoder - JsonObjectEncoder/Decoder are now used directly in JacksonJsonEncoder/Decoder - Codec uses MimeType instead of MediaType since they are not specific to HTTP - Default MimeType are now managed thanks to Encoder/Decoder#getSupportedMimeTypes() - AbstractEncoder/Decoder takes care of generic MimeType related behavior
This commit is contained in:
committed by
Rossen Stoyanchev
parent
141d75791d
commit
bdc5b38cb1
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.reactive.codec.decoder;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.util.MimeType;
|
||||
|
||||
/**
|
||||
* @author Sebastien Deleuze
|
||||
*/
|
||||
public abstract class AbstractDecoder<T> implements Decoder<T> {
|
||||
|
||||
private List<MimeType> supportedMimeTypes = Collections.emptyList();
|
||||
|
||||
public AbstractDecoder(MimeType... supportedMimeTypes) {
|
||||
this.supportedMimeTypes = Arrays.asList(supportedMimeTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canDecode(ResolvableType type, MimeType mimeType, Object... hints) {
|
||||
for (MimeType supportedMimeType : this.supportedMimeTypes) {
|
||||
if (supportedMimeType.isCompatibleWith(mimeType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MimeType> getSupportedMimeTypes() {
|
||||
return this.supportedMimeTypes;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,22 +21,28 @@ import java.nio.ByteBuffer;
|
||||
import org.reactivestreams.Publisher;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.MimeType;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
|
||||
/**
|
||||
* @author Sebastien Deleuze
|
||||
*/
|
||||
public class ByteBufferDecoder implements ByteToMessageDecoder<ByteBuffer> {
|
||||
public class ByteBufferDecoder extends AbstractDecoder<ByteBuffer> {
|
||||
|
||||
public ByteBufferDecoder() {
|
||||
super(MimeTypeUtils.ALL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canDecode(ResolvableType type, MediaType mediaType, Object... hints) {
|
||||
return ByteBuffer.class.isAssignableFrom(type.getRawClass());
|
||||
public boolean canDecode(ResolvableType type, MimeType mimeType, Object... hints) {
|
||||
return super.canDecode(type, mimeType, hints)
|
||||
&& ByteBuffer.class.isAssignableFrom(type.getRawClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Publisher<ByteBuffer> decode(Publisher<ByteBuffer> inputStream, ResolvableType type,
|
||||
MediaType mediaType, Object... hints) {
|
||||
MimeType mimeType, Object... hints) {
|
||||
|
||||
return inputStream;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,39 +17,45 @@
|
||||
package org.springframework.reactive.codec.decoder;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.reactive.codec.encoder.MessageToByteEncoder;
|
||||
import org.springframework.reactive.codec.encoder.Encoder;
|
||||
import org.springframework.util.MimeType;
|
||||
|
||||
/**
|
||||
* Decode from a bytes stream to a message stream.
|
||||
* Decode from a bytes stream to a stream of {@code T}.
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @see MessageToByteEncoder
|
||||
* @see Encoder
|
||||
*/
|
||||
public interface ByteToMessageDecoder<T> {
|
||||
public interface Decoder<T> {
|
||||
|
||||
/**
|
||||
* Indicate whether the given type and media type can be processed by this decoder.
|
||||
* @param type the stream element type to ultimately decode to.
|
||||
* @param mediaType the media type to decode from.
|
||||
* Typically the value of a {@code Content-Type} header for HTTP request.
|
||||
* Indicate whether the given type and mime type can be processed by this decoder.
|
||||
* @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 decodable; {@code false} otherwise
|
||||
* @return {@code true} if can process; {@code false} otherwise
|
||||
*/
|
||||
boolean canDecode(ResolvableType type, MediaType mediaType, Object... hints);
|
||||
boolean canDecode(ResolvableType type, MimeType mimeType, Object... hints);
|
||||
|
||||
/**
|
||||
* Decode a bytes stream to a message stream.
|
||||
* @param inputStream the input stream that represent the whole object to decode.
|
||||
* @param type the stream element type to ultimately decode to.
|
||||
* Decode an input {@link ByteBuffer} 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 decoded message stream
|
||||
* @return the output stream
|
||||
*/
|
||||
Publisher<T> decode(Publisher<ByteBuffer> inputStream, ResolvableType type,
|
||||
MediaType mediaType, Object... hints);
|
||||
Publisher<T> decode(Publisher<ByteBuffer> inputStream, ResolvableType type, MimeType mimeType, Object... hints);
|
||||
|
||||
/**
|
||||
* Return the list of {@link MimeType} objects supported by this codec.
|
||||
* @return the list of supported mime types
|
||||
*/
|
||||
List<MimeType> getSupportedMimeTypes();
|
||||
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package org.springframework.reactive.codec.decoder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.ObjectReader;
|
||||
@@ -25,10 +26,10 @@ import org.reactivestreams.Publisher;
|
||||
import reactor.Publishers;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.reactive.codec.CodecException;
|
||||
import org.springframework.reactive.codec.encoder.JacksonJsonEncoder;
|
||||
import org.springframework.reactive.io.ByteBufferInputStream;
|
||||
import org.springframework.util.MimeType;
|
||||
|
||||
/**
|
||||
* Decode from a bytes stream of JSON objects to a stream of {@code Object} (POJO).
|
||||
@@ -36,31 +37,36 @@ import org.springframework.reactive.io.ByteBufferInputStream;
|
||||
* @author Sebastien Deleuze
|
||||
* @see JacksonJsonEncoder
|
||||
*/
|
||||
public class JacksonJsonDecoder implements ByteToMessageDecoder<Object> {
|
||||
public class JacksonJsonDecoder extends AbstractDecoder<Object> {
|
||||
|
||||
private final ObjectMapper mapper;
|
||||
|
||||
private Decoder<ByteBuffer> preProcessor;
|
||||
|
||||
|
||||
public JacksonJsonDecoder() {
|
||||
this(new ObjectMapper());
|
||||
this(new ObjectMapper(), null);
|
||||
}
|
||||
|
||||
public JacksonJsonDecoder(ObjectMapper mapper) {
|
||||
public JacksonJsonDecoder(Decoder<ByteBuffer> preProcessor) {
|
||||
this(new ObjectMapper(), preProcessor);
|
||||
}
|
||||
|
||||
public JacksonJsonDecoder(ObjectMapper mapper, Decoder<ByteBuffer> preProcessor) {
|
||||
super(new MimeType("application", "json", StandardCharsets.UTF_8),
|
||||
new MimeType("application", "*+json", StandardCharsets.UTF_8));
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canDecode(ResolvableType type, MediaType mediaType, Object... hints) {
|
||||
return mediaType.isCompatibleWith(MediaType.APPLICATION_JSON);
|
||||
this.preProcessor = preProcessor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Publisher<Object> decode(Publisher<ByteBuffer> inputStream, ResolvableType type,
|
||||
MediaType mediaType, Object... hints) {
|
||||
MimeType mimeType, Object... hints) {
|
||||
|
||||
ObjectReader reader = this.mapper.readerFor(type.getRawClass());
|
||||
return Publishers.map(inputStream, chunk -> {
|
||||
Publisher<ByteBuffer> decodedStream = this.preProcessor == null ? inputStream :
|
||||
this.preProcessor.decode(inputStream, type, mimeType, hints);
|
||||
return Publishers.map(decodedStream, chunk -> {
|
||||
try {
|
||||
return reader.readValue(new ByteBufferInputStream(chunk));
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ import org.springframework.reactive.codec.CodecException;
|
||||
import org.springframework.reactive.codec.encoder.Jaxb2Encoder;
|
||||
import org.springframework.reactive.io.ByteBufferPublisherInputStream;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.MimeType;
|
||||
|
||||
/**
|
||||
* Decode from a bytes stream of XML elements to a stream of {@code Object} (POJO).
|
||||
@@ -49,20 +50,17 @@ import org.springframework.util.Assert;
|
||||
* @author Sebastien Deleuze
|
||||
* @see Jaxb2Encoder
|
||||
*/
|
||||
public class Jaxb2Decoder implements ByteToMessageDecoder<Object> {
|
||||
public class Jaxb2Decoder extends AbstractDecoder<Object> {
|
||||
|
||||
private final ConcurrentMap<Class<?>, JAXBContext> jaxbContexts = new ConcurrentHashMap<>(64);
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canDecode(ResolvableType type, MediaType mediaType, Object... hints) {
|
||||
return (mediaType.isCompatibleWith(MediaType.APPLICATION_XML) ||
|
||||
mediaType.isCompatibleWith(MediaType.TEXT_XML));
|
||||
public Jaxb2Decoder() {
|
||||
super(MediaType.APPLICATION_XML, MediaType.TEXT_XML);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Publisher<Object> decode(Publisher<ByteBuffer> inputStream, ResolvableType type,
|
||||
MediaType mediaType, Object... hints) {
|
||||
MimeType mimeType, Object... hints) {
|
||||
|
||||
Class<?> outputClass = type.getRawClass();
|
||||
try {
|
||||
@@ -129,4 +127,5 @@ public class Jaxb2Decoder implements ByteToMessageDecoder<Object> {
|
||||
}
|
||||
return jaxbContext;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.reactive.codec.decoder;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -28,8 +29,8 @@ import reactor.Publishers;
|
||||
import reactor.fn.Function;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.reactive.codec.encoder.JsonObjectEncoder;
|
||||
import org.springframework.util.MimeType;
|
||||
|
||||
/**
|
||||
* Decode an arbitrary split byte stream representing JSON objects to a byte
|
||||
@@ -45,7 +46,7 @@ import org.springframework.reactive.codec.encoder.JsonObjectEncoder;
|
||||
* @author Sebastien Deleuze
|
||||
* @see JsonObjectEncoder
|
||||
*/
|
||||
public class JsonObjectDecoder implements ByteToMessageDecoder<ByteBuffer> {
|
||||
public class JsonObjectDecoder extends AbstractDecoder<ByteBuffer> {
|
||||
|
||||
private static final int ST_CORRUPTED = -1;
|
||||
|
||||
@@ -85,6 +86,8 @@ public class JsonObjectDecoder implements ByteToMessageDecoder<ByteBuffer> {
|
||||
* "infinitely" many elements.
|
||||
*/
|
||||
public JsonObjectDecoder(int maxObjectLength, boolean streamArrayElements) {
|
||||
super(new MimeType("application", "json", StandardCharsets.UTF_8),
|
||||
new MimeType("application", "*+json", StandardCharsets.UTF_8));
|
||||
if (maxObjectLength < 1) {
|
||||
throw new IllegalArgumentException("maxObjectLength must be a positive int");
|
||||
}
|
||||
@@ -92,15 +95,9 @@ public class JsonObjectDecoder implements ByteToMessageDecoder<ByteBuffer> {
|
||||
this.streamArrayElements = streamArrayElements;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canDecode(ResolvableType type, MediaType mediaType, Object... hints) {
|
||||
return mediaType.isCompatibleWith(MediaType.APPLICATION_JSON);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Publisher<ByteBuffer> decode(Publisher<ByteBuffer> inputStream, ResolvableType type,
|
||||
MediaType mediaType, Object... hints) {
|
||||
MimeType mimeType, Object... hints) {
|
||||
|
||||
return Publishers.flatMap(inputStream, new Function<ByteBuffer, Publisher<? extends ByteBuffer>>() {
|
||||
|
||||
@@ -261,4 +258,5 @@ public class JsonObjectDecoder implements ByteToMessageDecoder<ByteBuffer> {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,9 +25,8 @@ import reactor.Publishers;
|
||||
import reactor.io.buffer.Buffer;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.reactive.codec.encoder.StringEncoder;
|
||||
import org.springframework.reactive.codec.support.HintUtils;
|
||||
import org.springframework.util.MimeType;
|
||||
|
||||
/**
|
||||
* Decode from a bytes stream to a String stream.
|
||||
@@ -35,22 +34,31 @@ import org.springframework.reactive.codec.support.HintUtils;
|
||||
* @author Sebastien Deleuze
|
||||
* @see StringEncoder
|
||||
*/
|
||||
public class StringDecoder implements ByteToMessageDecoder<String> {
|
||||
public class StringDecoder extends AbstractDecoder<String> {
|
||||
|
||||
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
|
||||
|
||||
public StringDecoder() {
|
||||
super(new MimeType("text", "plain", DEFAULT_CHARSET));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canDecode(ResolvableType type, MediaType mediaType, Object... hints) {
|
||||
return mediaType.isCompatibleWith(MediaType.TEXT_PLAIN)
|
||||
public boolean canDecode(ResolvableType type, MimeType mimeType, Object... hints) {
|
||||
return super.canDecode(type, mimeType, hints)
|
||||
&& String.class.isAssignableFrom(type.getRawClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Publisher<String> decode(Publisher<ByteBuffer> inputStream, ResolvableType type,
|
||||
MediaType mediaType, Object... hints) {
|
||||
MimeType mimeType, Object... hints) {
|
||||
|
||||
Charset charset = HintUtils.getHintByClass(Charset.class, hints, DEFAULT_CHARSET);
|
||||
Charset charset;
|
||||
if (mimeType != null && mimeType.getCharSet() != null) {
|
||||
charset = mimeType.getCharSet();
|
||||
}
|
||||
else {
|
||||
charset = DEFAULT_CHARSET;
|
||||
}
|
||||
return Publishers.map(inputStream, chunk -> new String(new Buffer(chunk).asBytes(), charset));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.reactive.codec.encoder;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.util.MimeType;
|
||||
|
||||
/**
|
||||
* @author Sebastien Deleuze
|
||||
*/
|
||||
public abstract class AbstractEncoder<T> implements Encoder<T> {
|
||||
|
||||
private List<MimeType> supportedMimeTypes = Collections.emptyList();
|
||||
|
||||
public AbstractEncoder(MimeType... supportedMimeTypes) {
|
||||
this.supportedMimeTypes = Arrays.asList(supportedMimeTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEncode(ResolvableType type, MimeType mimeType, Object... hints) {
|
||||
for (MimeType supportedMimeType : this.supportedMimeTypes) {
|
||||
if (supportedMimeType.isCompatibleWith(mimeType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MimeType> getSupportedMimeTypes() {
|
||||
return this.supportedMimeTypes;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,24 +21,28 @@ import java.nio.ByteBuffer;
|
||||
import org.reactivestreams.Publisher;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.MimeType;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
|
||||
/**
|
||||
* @author Sebastien Deleuze
|
||||
*/
|
||||
public class ByteBufferEncoder implements MessageToByteEncoder<ByteBuffer> {
|
||||
public class ByteBufferEncoder extends AbstractEncoder<ByteBuffer> {
|
||||
|
||||
@Override
|
||||
public boolean canEncode(ResolvableType type, MediaType mediaType, Object... hints) {
|
||||
return ByteBuffer.class.isAssignableFrom(type.getRawClass());
|
||||
public ByteBufferEncoder() {
|
||||
super(MimeTypeUtils.ALL);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Publisher<ByteBuffer> encode(Publisher<? extends ByteBuffer> messageStream,
|
||||
ResolvableType type, MediaType mediaType, Object... hints) {
|
||||
|
||||
return (Publisher<ByteBuffer>) messageStream;
|
||||
public boolean canEncode(ResolvableType type, MimeType mimeType, Object... hints) {
|
||||
return super.canEncode(type, mimeType, hints)
|
||||
&& ByteBuffer.class.isAssignableFrom(type.getRawClass());
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public Publisher<ByteBuffer> encode(Publisher<? extends ByteBuffer> inputStream, ResolvableType type,
|
||||
MimeType mimeType, Object... hints) {
|
||||
|
||||
return (Publisher<ByteBuffer>)inputStream;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.reactive.codec.encoder;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.reactive.codec.decoder.Decoder;
|
||||
import org.springframework.util.MimeType;
|
||||
|
||||
/**
|
||||
* Encode from a stream of {@code T} to a bytes stream.
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @see Decoder
|
||||
*/
|
||||
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
|
||||
*/
|
||||
boolean canEncode(ResolvableType type, MimeType mimeType, Object... hints);
|
||||
|
||||
/**
|
||||
* Encode an input stream of {@code T} to an output {@link ByteBuffer} stream.
|
||||
* @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
|
||||
*/
|
||||
Publisher<ByteBuffer> encode(Publisher<? extends T> inputStream, ResolvableType type, MimeType mimeType, Object... hints);
|
||||
|
||||
/**
|
||||
* Return the list of {@link MimeType} objects supported by this codec.
|
||||
* @return the list of supported mime types
|
||||
*/
|
||||
List<MimeType> getSupportedMimeTypes();
|
||||
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package org.springframework.reactive.codec.encoder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.reactivestreams.Publisher;
|
||||
@@ -25,10 +26,10 @@ import reactor.Publishers;
|
||||
import reactor.io.buffer.Buffer;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.reactive.codec.CodecException;
|
||||
import org.springframework.reactive.codec.decoder.JacksonJsonDecoder;
|
||||
import org.springframework.reactive.io.BufferOutputStream;
|
||||
import org.springframework.util.MimeType;
|
||||
|
||||
/**
|
||||
* Encode from an {@code Object} stream to a byte stream of JSON objects.
|
||||
@@ -36,28 +37,32 @@ import org.springframework.reactive.io.BufferOutputStream;
|
||||
* @author Sebastien Deleuze
|
||||
* @see JacksonJsonDecoder
|
||||
*/
|
||||
public class JacksonJsonEncoder implements MessageToByteEncoder<Object> {
|
||||
public class JacksonJsonEncoder extends AbstractEncoder<Object> {
|
||||
|
||||
private final ObjectMapper mapper;
|
||||
|
||||
private Encoder<ByteBuffer> postProcessor;
|
||||
|
||||
public JacksonJsonEncoder() {
|
||||
this(new ObjectMapper());
|
||||
this(new ObjectMapper(), null);
|
||||
}
|
||||
|
||||
public JacksonJsonEncoder(ObjectMapper mapper) {
|
||||
public JacksonJsonEncoder(Encoder<ByteBuffer> postProcessor) {
|
||||
this(new ObjectMapper(), postProcessor);
|
||||
}
|
||||
|
||||
public JacksonJsonEncoder(ObjectMapper mapper, Encoder<ByteBuffer> postProcessor) {
|
||||
super(new MimeType("application", "json", StandardCharsets.UTF_8),
|
||||
new MimeType("application", "*+json", StandardCharsets.UTF_8));
|
||||
this.mapper = mapper;
|
||||
this.postProcessor = postProcessor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEncode(ResolvableType type, MediaType mediaType, Object... hints) {
|
||||
return mediaType.isCompatibleWith(MediaType.APPLICATION_JSON);
|
||||
}
|
||||
public Publisher<ByteBuffer> encode(Publisher<? extends Object> inputStream,
|
||||
ResolvableType type, MimeType mimeType, Object... hints) {
|
||||
|
||||
@Override
|
||||
public Publisher<ByteBuffer> encode(Publisher<? extends Object> messageStream,
|
||||
ResolvableType type, MediaType mediaType, Object... hints) {
|
||||
|
||||
return Publishers.map(messageStream, value -> {
|
||||
Publisher<ByteBuffer> stream = Publishers.map(inputStream, value -> {
|
||||
Buffer buffer = new Buffer();
|
||||
BufferOutputStream outputStream = new BufferOutputStream(buffer);
|
||||
try {
|
||||
@@ -68,6 +73,7 @@ public class JacksonJsonEncoder implements MessageToByteEncoder<Object> {
|
||||
buffer.flip();
|
||||
return buffer.byteBuffer();
|
||||
});
|
||||
return this.postProcessor == null ? stream : this.postProcessor.encode(stream, type, mimeType, hints);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.springframework.reactive.codec.decoder.Jaxb2Decoder;
|
||||
import org.springframework.reactive.io.BufferOutputStream;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.MimeType;
|
||||
|
||||
/**
|
||||
* Encode from an {@code Object} stream to a byte stream of XML elements.
|
||||
@@ -43,20 +44,18 @@ import org.springframework.util.ClassUtils;
|
||||
* @author Sebastien Deleuze
|
||||
* @see Jaxb2Decoder
|
||||
*/
|
||||
public class Jaxb2Encoder implements MessageToByteEncoder<Object> {
|
||||
public class Jaxb2Encoder extends AbstractEncoder<Object> {
|
||||
|
||||
private final ConcurrentMap<Class<?>, JAXBContext> jaxbContexts = new ConcurrentHashMap<>(64);
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canEncode(ResolvableType type, MediaType mediaType, Object... hints) {
|
||||
return (mediaType.isCompatibleWith(MediaType.APPLICATION_XML) ||
|
||||
mediaType.isCompatibleWith(MediaType.TEXT_XML));
|
||||
public Jaxb2Encoder() {
|
||||
super(MediaType.APPLICATION_XML, MediaType.TEXT_XML);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Publisher<ByteBuffer> encode(Publisher<? extends Object> messageStream, ResolvableType type,
|
||||
MediaType mediaType, Object... hints) {
|
||||
MimeType mimeType, Object... hints) {
|
||||
|
||||
return Publishers.map(messageStream, value -> {
|
||||
try {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.reactive.codec.encoder;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
|
||||
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
|
||||
|
||||
@@ -27,8 +28,8 @@ import reactor.core.support.BackpressureUtils;
|
||||
import reactor.io.buffer.Buffer;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.reactive.codec.decoder.JsonObjectDecoder;
|
||||
import org.springframework.util.MimeType;
|
||||
|
||||
import static reactor.Publishers.lift;
|
||||
|
||||
@@ -41,17 +42,16 @@ import static reactor.Publishers.lift;
|
||||
*
|
||||
* @see JsonObjectDecoder
|
||||
*/
|
||||
public class JsonObjectEncoder implements MessageToByteEncoder<ByteBuffer> {
|
||||
public class JsonObjectEncoder extends AbstractEncoder<ByteBuffer> {
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canEncode(ResolvableType type, MediaType mediaType, Object... hints) {
|
||||
return mediaType.isCompatibleWith(MediaType.APPLICATION_JSON);
|
||||
public JsonObjectEncoder() {
|
||||
super(new MimeType("application", "json", StandardCharsets.UTF_8),
|
||||
new MimeType("application", "*+json", StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Publisher<ByteBuffer> encode(Publisher<? extends ByteBuffer> messageStream,
|
||||
ResolvableType type, MediaType mediaType, Object... hints) {
|
||||
ResolvableType type, MimeType mimeType, Object... hints) {
|
||||
|
||||
//noinspection Convert2MethodRef
|
||||
return lift(messageStream, bbs -> new JsonEncoderBarrier(bbs));
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.reactive.codec.encoder;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.reactive.codec.decoder.ByteToMessageDecoder;
|
||||
|
||||
/**
|
||||
* Encode from a message stream to a bytes stream.
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @see ByteToMessageDecoder
|
||||
*/
|
||||
public interface MessageToByteEncoder<T> {
|
||||
|
||||
/**
|
||||
* Indicate whether the given type and media type can be processed by this encoder.
|
||||
* @param type the stream element type to encode.
|
||||
* @param mediaType the media type to encode.
|
||||
* Typically the value of an {@code Accept} header for HTTP request.
|
||||
* @param hints Additional information about how to encode, optional.
|
||||
* @return {@code true} if encodable; {@code false} otherwise
|
||||
*/
|
||||
boolean canEncode(ResolvableType type, MediaType mediaType, Object... hints);
|
||||
|
||||
/**
|
||||
* Encode a given message stream to the given output byte stream.
|
||||
* @param messageStream the message stream to encode.
|
||||
* @param type the stream element type to encode.
|
||||
* @param mediaType the media type to encode.
|
||||
* Typically the value of an {@code Accept} header for HTTP request.
|
||||
* @param hints Additional information about how to encode, optional.
|
||||
* @return the encoded bytes stream
|
||||
*/
|
||||
Publisher<ByteBuffer> encode(Publisher<? extends T> messageStream, ResolvableType type,
|
||||
MediaType mediaType, Object... hints);
|
||||
|
||||
}
|
||||
@@ -24,9 +24,8 @@ import org.reactivestreams.Publisher;
|
||||
import reactor.Publishers;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.reactive.codec.decoder.StringDecoder;
|
||||
import org.springframework.reactive.codec.support.HintUtils;
|
||||
import org.springframework.util.MimeType;
|
||||
|
||||
/**
|
||||
* Encode from a String stream to a bytes stream.
|
||||
@@ -34,22 +33,32 @@ import org.springframework.reactive.codec.support.HintUtils;
|
||||
* @author Sebastien Deleuze
|
||||
* @see StringDecoder
|
||||
*/
|
||||
public class StringEncoder implements MessageToByteEncoder<String> {
|
||||
public class StringEncoder extends AbstractEncoder<String> {
|
||||
|
||||
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
|
||||
|
||||
|
||||
public StringEncoder() {
|
||||
super(new MimeType("text", "plain", DEFAULT_CHARSET));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEncode(ResolvableType type, MediaType mediaType, Object... hints) {
|
||||
return mediaType.isCompatibleWith(MediaType.TEXT_PLAIN)
|
||||
public boolean canEncode(ResolvableType type, MimeType mimeType, Object... hints) {
|
||||
return super.canEncode(type, mimeType, hints)
|
||||
&& String.class.isAssignableFrom(type.getRawClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Publisher<ByteBuffer> encode(Publisher<? extends String> elementStream,
|
||||
ResolvableType type, MediaType mediaType, Object... hints) {
|
||||
ResolvableType type, MimeType mimeType, Object... hints) {
|
||||
|
||||
final Charset charset = HintUtils.getHintByClass(Charset.class, hints, DEFAULT_CHARSET);
|
||||
Charset charset;
|
||||
if (mimeType != null && mimeType.getCharSet() != null) {
|
||||
charset = mimeType.getCharSet();
|
||||
}
|
||||
else {
|
||||
charset = DEFAULT_CHARSET;
|
||||
}
|
||||
return Publishers.map(elementStream, s -> ByteBuffer.wrap(s.getBytes(charset)));
|
||||
}
|
||||
|
||||
|
||||
@@ -16,15 +16,15 @@
|
||||
|
||||
package org.springframework.reactive.codec.support;
|
||||
|
||||
import org.springframework.reactive.codec.decoder.ByteToMessageDecoder;
|
||||
import org.springframework.reactive.codec.encoder.MessageToByteEncoder;
|
||||
import org.springframework.reactive.codec.decoder.Decoder;
|
||||
import org.springframework.reactive.codec.encoder.Encoder;
|
||||
|
||||
/**
|
||||
* Utility methods for dealing with codec hints.
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @see MessageToByteEncoder
|
||||
* @see ByteToMessageDecoder
|
||||
* @see Encoder
|
||||
* @see Decoder
|
||||
*/
|
||||
public abstract class HintUtils {
|
||||
|
||||
|
||||
@@ -17,10 +17,6 @@
|
||||
package org.springframework.reactive.web.dispatch.method.annotation;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
@@ -32,8 +28,7 @@ import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.ReactiveServerHttpRequest;
|
||||
import org.springframework.reactive.codec.decoder.ByteToMessageDecoder;
|
||||
import org.springframework.reactive.codec.decoder.JsonObjectDecoder;
|
||||
import org.springframework.reactive.codec.decoder.Decoder;
|
||||
import org.springframework.reactive.web.dispatch.method.HandlerMethodArgumentResolver;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@@ -44,21 +39,15 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
*/
|
||||
public class RequestBodyArgumentResolver implements HandlerMethodArgumentResolver {
|
||||
|
||||
private static final Charset UTF_8 = Charset.forName("UTF-8");
|
||||
|
||||
|
||||
private final List<ByteToMessageDecoder<?>> decoders;
|
||||
private final List<Decoder<?>> deserializers;
|
||||
|
||||
private final ConversionService conversionService;
|
||||
|
||||
// TODO: remove field
|
||||
private final List<ByteToMessageDecoder<ByteBuffer>> preProcessors = Arrays.asList(new JsonObjectDecoder());
|
||||
|
||||
|
||||
public RequestBodyArgumentResolver(List<ByteToMessageDecoder<?>> decoders, ConversionService service) {
|
||||
Assert.notEmpty(decoders, "At least one decoder is required.");
|
||||
public RequestBodyArgumentResolver(List<Decoder<?>> deserializers, ConversionService service) {
|
||||
Assert.notEmpty(deserializers, "At least one deserializer is required.");
|
||||
Assert.notNull(service, "'conversionService' is required.");
|
||||
this.decoders = decoders;
|
||||
this.deserializers = deserializers;
|
||||
this.conversionService = service;
|
||||
}
|
||||
|
||||
@@ -72,20 +61,12 @@ public class RequestBodyArgumentResolver implements HandlerMethodArgumentResolve
|
||||
public Publisher<Object> resolveArgument(MethodParameter parameter, ReactiveServerHttpRequest request) {
|
||||
MediaType mediaType = resolveMediaType(request);
|
||||
ResolvableType type = ResolvableType.forMethodParameter(parameter);
|
||||
List<Object> hints = new ArrayList<>();
|
||||
hints.add(UTF_8);
|
||||
Publisher<ByteBuffer> inputStream = request.getBody();
|
||||
Publisher<?> elementStream = inputStream;
|
||||
ResolvableType elementType = type.hasGenerics() ? type.getGeneric(0) : type;
|
||||
ByteToMessageDecoder<?> decoder = resolveDecoder(elementType, mediaType, hints.toArray());
|
||||
if (decoder != null) {
|
||||
List<ByteToMessageDecoder<ByteBuffer>> preProcessors = resolvePreProcessors(
|
||||
elementType, mediaType,hints.toArray());
|
||||
|
||||
for (ByteToMessageDecoder<ByteBuffer> preProcessor : preProcessors) {
|
||||
inputStream = preProcessor.decode(inputStream, elementType, mediaType, hints.toArray());
|
||||
}
|
||||
elementStream = decoder.decode(inputStream, elementType, mediaType, hints.toArray());
|
||||
Decoder<?> deserializer = resolveDeserializer(elementType, mediaType);
|
||||
if (deserializer != null) {
|
||||
elementStream = deserializer.decode(inputStream, elementType, mediaType);
|
||||
}
|
||||
if (this.conversionService.canConvert(Publisher.class, type.getRawClass())) {
|
||||
return Publishers.just(this.conversionService.convert(elementStream, type.getRawClass()));
|
||||
@@ -100,8 +81,8 @@ public class RequestBodyArgumentResolver implements HandlerMethodArgumentResolve
|
||||
return ( mediaTypes.size() > 0 ? mediaTypes.get(0) : MediaType.TEXT_PLAIN);
|
||||
}
|
||||
|
||||
private ByteToMessageDecoder<?> resolveDecoder(ResolvableType type, MediaType mediaType, Object[] hints) {
|
||||
for (ByteToMessageDecoder<?> deserializer : this.decoders) {
|
||||
private Decoder<?> resolveDeserializer(ResolvableType type, MediaType mediaType, Object... hints) {
|
||||
for (Decoder<?> deserializer : this.deserializers) {
|
||||
if (deserializer.canDecode(type, mediaType, hints)) {
|
||||
return deserializer;
|
||||
}
|
||||
@@ -109,16 +90,4 @@ public class RequestBodyArgumentResolver implements HandlerMethodArgumentResolve
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<ByteToMessageDecoder<ByteBuffer>> resolvePreProcessors(ResolvableType type,
|
||||
MediaType mediaType, Object[] hints) {
|
||||
|
||||
List<ByteToMessageDecoder<ByteBuffer>> preProcessors = new ArrayList<>();
|
||||
for (ByteToMessageDecoder<ByteBuffer> preProcessor : this.preProcessors) {
|
||||
if (preProcessor.canDecode(type, mediaType, hints)) {
|
||||
preProcessors.add(preProcessor);
|
||||
}
|
||||
}
|
||||
return preProcessors;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,8 +28,9 @@ import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.http.server.ReactiveServerHttpRequest;
|
||||
import org.springframework.http.server.ReactiveServerHttpResponse;
|
||||
import org.springframework.reactive.codec.decoder.ByteBufferDecoder;
|
||||
import org.springframework.reactive.codec.decoder.ByteToMessageDecoder;
|
||||
import org.springframework.reactive.codec.decoder.Decoder;
|
||||
import org.springframework.reactive.codec.decoder.JacksonJsonDecoder;
|
||||
import org.springframework.reactive.codec.decoder.JsonObjectDecoder;
|
||||
import org.springframework.reactive.codec.decoder.StringDecoder;
|
||||
import org.springframework.reactive.web.dispatch.HandlerAdapter;
|
||||
import org.springframework.reactive.web.dispatch.HandlerResult;
|
||||
@@ -70,8 +71,8 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Initializin
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (this.argumentResolvers == null) {
|
||||
|
||||
List<ByteToMessageDecoder<?>> decoders = Arrays.asList(new ByteBufferDecoder(),
|
||||
new StringDecoder(), new JacksonJsonDecoder());
|
||||
List<Decoder<?>> decoders = Arrays.asList(new ByteBufferDecoder(),
|
||||
new StringDecoder(), new JacksonJsonDecoder(new JsonObjectDecoder()));
|
||||
|
||||
this.argumentResolvers = new ArrayList<>();
|
||||
this.argumentResolvers.add(new RequestParamArgumentResolver());
|
||||
|
||||
@@ -18,9 +18,6 @@ package org.springframework.reactive.web.dispatch.method.annotation;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
@@ -35,42 +32,33 @@ import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.ReactiveServerHttpRequest;
|
||||
import org.springframework.http.server.ReactiveServerHttpResponse;
|
||||
import org.springframework.reactive.codec.encoder.JsonObjectEncoder;
|
||||
import org.springframework.reactive.codec.encoder.MessageToByteEncoder;
|
||||
import org.springframework.reactive.codec.encoder.Encoder;
|
||||
import org.springframework.reactive.web.dispatch.HandlerResult;
|
||||
import org.springframework.reactive.web.dispatch.HandlerResultHandler;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.MimeType;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
|
||||
|
||||
/**
|
||||
* First version using {@link MessageToByteEncoder}s
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Stephane Maldini
|
||||
* @author Sebastien Deleuze
|
||||
*/
|
||||
public class ResponseBodyResultHandler implements HandlerResultHandler, Ordered {
|
||||
|
||||
private static final Charset UTF_8 = Charset.forName("UTF-8");
|
||||
|
||||
|
||||
private final List<MessageToByteEncoder<?>> serializers;
|
||||
private final List<Encoder<?>> serializers;
|
||||
|
||||
private final ConversionService conversionService;
|
||||
|
||||
private int order = 0;
|
||||
|
||||
// TODO: remove field
|
||||
private final List<MessageToByteEncoder<ByteBuffer>> postProcessors = Arrays.asList(new JsonObjectEncoder());
|
||||
|
||||
|
||||
|
||||
public ResponseBodyResultHandler(List<MessageToByteEncoder<?>> encoders, ConversionService service) {
|
||||
Assert.notEmpty(encoders, "At least one encoder is required.");
|
||||
public ResponseBodyResultHandler(List<Encoder<?>> serializers, ConversionService service) {
|
||||
Assert.notEmpty(serializers, "At least one serializers is required.");
|
||||
Assert.notNull(service, "'conversionService' is required.");
|
||||
this.serializers = encoders;
|
||||
this.serializers = serializers;
|
||||
this.conversionService = service;
|
||||
}
|
||||
|
||||
@@ -110,9 +98,7 @@ public class ResponseBodyResultHandler implements HandlerResultHandler, Ordered
|
||||
|
||||
ResolvableType type = ResolvableType.forMethodParameter(returnType);
|
||||
MediaType mediaType = resolveMediaType(request);
|
||||
List<Object> hints = new ArrayList<>();
|
||||
hints.add(UTF_8);
|
||||
Publisher<Object> elementStream;
|
||||
Publisher<?> elementStream;
|
||||
ResolvableType elementType;
|
||||
if (conversionService.canConvert(type.getRawClass(), Publisher.class)) {
|
||||
elementStream = conversionService.convert(value, Publisher.class);
|
||||
@@ -123,17 +109,20 @@ public class ResponseBodyResultHandler implements HandlerResultHandler, Ordered
|
||||
elementType = type;
|
||||
}
|
||||
|
||||
MessageToByteEncoder<Object> encoder = (MessageToByteEncoder<Object>) resolveEncoder(
|
||||
elementType, mediaType, hints.toArray());
|
||||
Encoder<?> serializer = resolveSerializer(elementType, mediaType);
|
||||
|
||||
if (encoder != null) {
|
||||
Publisher<ByteBuffer> outputStream = encoder.encode(elementStream, type, mediaType, hints.toArray());
|
||||
List<MessageToByteEncoder<ByteBuffer>> postProcessors = resolvePostProcessors(
|
||||
elementType, mediaType, hints.toArray());
|
||||
for (MessageToByteEncoder<ByteBuffer> postProcessor : postProcessors) {
|
||||
outputStream = postProcessor.encode(outputStream, elementType, mediaType, hints.toArray());
|
||||
if (serializer != null) {
|
||||
Publisher<ByteBuffer> outputStream = serializer.encode((Publisher)elementStream, type, mediaType);
|
||||
if (mediaType == null || mediaType.isWildcardType() || mediaType.isWildcardSubtype()) {
|
||||
List<MimeType> mimeTypes = serializer.getSupportedMimeTypes();
|
||||
if (!mimeTypes.isEmpty()) {
|
||||
MimeType mimeType = mimeTypes.get(0);
|
||||
mediaType = new MediaType(mimeType.getType(), mimeType.getSubtype(), mimeType.getParameters());
|
||||
}
|
||||
}
|
||||
if (mediaType != null && !mediaType.equals(MediaType.ALL)) {
|
||||
response.getHeaders().setContentType(mediaType);
|
||||
}
|
||||
response.getHeaders().setContentType(mediaType);
|
||||
return response.setBody(outputStream);
|
||||
}
|
||||
String returnTypeName = returnType.getParameterType().getName();
|
||||
@@ -148,25 +137,13 @@ public class ResponseBodyResultHandler implements HandlerResultHandler, Ordered
|
||||
return ( mediaTypes.size() > 0 ? mediaTypes.get(0) : MediaType.TEXT_PLAIN);
|
||||
}
|
||||
|
||||
private MessageToByteEncoder<?> resolveEncoder(ResolvableType type, MediaType mediaType, Object[] hints) {
|
||||
for (MessageToByteEncoder<?> codec : this.serializers) {
|
||||
if (codec.canEncode(type, mediaType, hints)) {
|
||||
return codec;
|
||||
private Encoder<?> resolveSerializer(ResolvableType type, MediaType mediaType, Object... hints) {
|
||||
for (Encoder<?> serializer : this.serializers) {
|
||||
if (serializer.canEncode(type, mediaType, hints)) {
|
||||
return serializer;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<MessageToByteEncoder<ByteBuffer>> resolvePostProcessors(ResolvableType type,
|
||||
MediaType mediaType, Object[] hints) {
|
||||
|
||||
List<MessageToByteEncoder<ByteBuffer>> postProcessors = new ArrayList<>();
|
||||
for (MessageToByteEncoder<ByteBuffer> postProcessor : this.postProcessors) {
|
||||
if (postProcessor.canEncode(type, mediaType, hints)) {
|
||||
postProcessors.add(postProcessor);
|
||||
}
|
||||
}
|
||||
return postProcessors;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ import org.springframework.http.MediaType;
|
||||
/**
|
||||
* @author Sebastien Deleuze
|
||||
*/
|
||||
public class ByteBufferDecoderEncoder {
|
||||
public class ByteBufferEncoderTests {
|
||||
|
||||
private final ByteBufferEncoder encoder = new ByteBufferEncoder();
|
||||
|
||||
@@ -39,7 +39,6 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.core.convert.support.ReactiveStreamsToCompletableFutureConverter;
|
||||
import org.springframework.core.convert.support.ReactiveStreamsToReactorConverter;
|
||||
@@ -50,6 +49,7 @@ import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.reactive.codec.encoder.ByteBufferEncoder;
|
||||
import org.springframework.reactive.codec.encoder.JacksonJsonEncoder;
|
||||
import org.springframework.reactive.codec.encoder.JsonObjectEncoder;
|
||||
import org.springframework.reactive.codec.encoder.StringEncoder;
|
||||
import org.springframework.reactive.web.dispatch.DispatcherHandler;
|
||||
import org.springframework.reactive.web.dispatch.SimpleHandlerResultHandler;
|
||||
@@ -290,7 +290,7 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati
|
||||
@Bean
|
||||
public ResponseBodyResultHandler responseBodyResultHandler() {
|
||||
return new ResponseBodyResultHandler(Arrays.asList(
|
||||
new ByteBufferEncoder(), new StringEncoder(),new JacksonJsonEncoder()),
|
||||
new ByteBufferEncoder(), new StringEncoder(), new JacksonJsonEncoder(new JsonObjectEncoder())),
|
||||
conversionService());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user