content-length support in EncoderHttpMessageWriter

EncoderHttpMessageWriter checks explicitly for Mono publishers and sets
the content length, if it is known for the given data item.

Issue: SPR-16542
This commit is contained in:
Rossen Stoyanchev
2018-02-27 16:53:29 -05:00
parent 7a8e0ff3c3
commit 27815847b1
9 changed files with 106 additions and 41 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
@@ -55,4 +55,8 @@ public class ByteArrayEncoder extends AbstractEncoder<byte[]> {
return Flux.from(inputStream).map(bufferFactory::wrap);
}
@Override
public Long getContentLength(byte[] bytes, @Nullable MimeType mimeType) {
return (long) bytes.length;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
@@ -56,4 +56,8 @@ public class ByteBufferEncoder extends AbstractEncoder<ByteBuffer> {
return Flux.from(inputStream).map(bufferFactory::wrap);
}
@Override
public Long getContentLength(ByteBuffer byteBuffer, @Nullable MimeType mimeType) {
return (long) byteBuffer.array().length;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
@@ -62,13 +62,8 @@ public class CharSequenceEncoder extends AbstractEncoder<CharSequence> {
DataBufferFactory bufferFactory, ResolvableType elementType,
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
Charset charset;
if (mimeType != null && mimeType.getCharset() != null) {
charset = mimeType.getCharset();
}
else {
charset = DEFAULT_CHARSET;
}
Charset charset = getCharset(mimeType);
return Flux.from(inputStream).map(charSequence -> {
CharBuffer charBuffer = CharBuffer.wrap(charSequence);
ByteBuffer byteBuffer = charset.encode(charBuffer);
@@ -76,6 +71,21 @@ public class CharSequenceEncoder extends AbstractEncoder<CharSequence> {
});
}
private Charset getCharset(@Nullable MimeType mimeType) {
Charset charset;
if (mimeType != null && mimeType.getCharset() != null) {
charset = mimeType.getCharset();
}
else {
charset = DEFAULT_CHARSET;
}
return charset;
}
@Override
public Long getContentLength(CharSequence data, @Nullable MimeType mimeType) {
return (long) data.toString().getBytes(getCharset(mimeType)).length;
}
/**
* Create a {@code CharSequenceEncoder} that supports only "text/plain".

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
@@ -55,4 +55,8 @@ public class DataBufferEncoder extends AbstractEncoder<DataBuffer> {
return Flux.from(inputStream);
}
@Override
public Long getContentLength(DataBuffer dataBuffer, MimeType mimeType) {
return (long) dataBuffer.readableByteCount();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 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.
@@ -67,6 +67,17 @@ public interface Encoder<T> {
Flux<DataBuffer> encode(Publisher<? extends T> inputStream, DataBufferFactory bufferFactory,
ResolvableType elementType, @Nullable MimeType mimeType, @Nullable Map<String, Object> hints);
/**
* Return the length for the given item, if known.
* @param t the item to check
* @return the length in bytes, or {@code null} if not known.
* @since 5.0.5
*/
@Nullable
default Long getContentLength(T t, @Nullable MimeType mimeType) {
return null;
}
/**
* Return the list of mime types this encoder supports.
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
@@ -16,11 +16,14 @@
package org.springframework.core.codec;
import java.io.IOException;
import java.util.Map;
import java.util.OptionalLong;
import reactor.core.publisher.Flux;
import org.springframework.core.ResolvableType;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
@@ -68,4 +71,17 @@ public class ResourceEncoder extends AbstractSingleValueEncoder<Resource> {
return DataBufferUtils.read(resource, dataBufferFactory, this.bufferSize);
}
@Override
public Long getContentLength(Resource resource, @Nullable MimeType mimeType) {
// Don't consume InputStream...
if (InputStreamResource.class != resource.getClass()) {
try {
return resource.contentLength();
}
catch (IOException ignored) {
}
}
return null;
}
}