diff --git a/spring-core/src/main/java/org/springframework/core/codec/CharSequenceEncoder.java b/spring-core/src/main/java/org/springframework/core/codec/CharSequenceEncoder.java index f2e1642ed0..25ae5a517d 100644 --- a/spring-core/src/main/java/org/springframework/core/codec/CharSequenceEncoder.java +++ b/spring-core/src/main/java/org/springframework/core/codec/CharSequenceEncoder.java @@ -20,6 +20,8 @@ import java.nio.charset.Charset; import java.nio.charset.CoderMalfunctionError; import java.nio.charset.StandardCharsets; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; @@ -49,6 +51,9 @@ public final class CharSequenceEncoder extends AbstractEncoder { */ public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; + private final ConcurrentMap charsetToMaxBytesPerChar = + new ConcurrentHashMap<>(3); + private CharSequenceEncoder(MimeType... mimeTypes) { super(mimeTypes); @@ -76,7 +81,8 @@ public final class CharSequenceEncoder extends AbstractEncoder { }); } boolean release = true; - DataBuffer dataBuffer = bufferFactory.allocateBuffer(); + int capacity = calculateCapacity(charSequence, charset); + DataBuffer dataBuffer = bufferFactory.allocateBuffer(capacity); try { dataBuffer.write(charSequence, charset); release = false; @@ -93,6 +99,13 @@ public final class CharSequenceEncoder extends AbstractEncoder { }); } + private int calculateCapacity(CharSequence sequence, Charset charset) { + float maxBytesPerChar = this.charsetToMaxBytesPerChar + .computeIfAbsent(charset, cs -> cs.newEncoder().maxBytesPerChar()); + float maxBytesForSequence = sequence.length() * maxBytesPerChar; + return (int) Math.ceil(maxBytesForSequence); + } + private Charset getCharset(@Nullable MimeType mimeType) { if (mimeType != null && mimeType.getCharset() != null) { return mimeType.getCharset();