diff --git a/spring-core/src/main/java/org/springframework/util/StreamUtils.java b/spring-core/src/main/java/org/springframework/util/StreamUtils.java index bf0f708f6f..881b6d7d14 100644 --- a/spring-core/src/main/java/org/springframework/util/StreamUtils.java +++ b/spring-core/src/main/java/org/springframework/util/StreamUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 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. @@ -93,6 +93,27 @@ public abstract class StreamUtils { return out.toString(); } + /** + * Copy the contents of the given {@link ByteArrayOutputStream} into a {@link String}. + *
This is a more effective equivalent of {@code new String(baos.toByteArray(), charset)}. + *
As long as the {@code charset} is already available at the point of + * invocation, no exception is expected to be thrown by this method. + * @param baos the {@code ByteArrayOutputStream} to be copied into a String + * @param charset the {@link Charset} to use to decode the bytes + * @return the String that has been copied to (possibly empty) + * @since 5.2.6 + */ + public static String copyToString(ByteArrayOutputStream baos, Charset charset) { + Assert.notNull(baos, "No ByteArrayOutputStream specified"); + Assert.notNull(charset, "No Charset specified"); + try { + return baos.toString(charset.name()); + } + catch (UnsupportedEncodingException ex) { + throw new RuntimeException("Failed to copy contents of ByteArrayOutputStream into a String", ex); + } + } + /** * Copy the contents of the given byte array to the given OutputStream. * Leaves the stream open when done. @@ -239,25 +260,6 @@ public abstract class StreamUtils { return new NonClosingOutputStream(out); } - /** - * More effective equivalent of {@code new String(baos.toByteArray(), charset)} - * As far as at invocation point {@code charset} is already available, - * no exception is expected to be thrown. - * - * @param baos {@link ByteArrayOutputStream} to be flushed into String - * @param charset applicable {@link Charset} - * @return String represenation of bytes stored in {@code baos} - */ - public static String baosToString(ByteArrayOutputStream baos, Charset charset) { - Assert.notNull(baos, "No ByteArrayOutputStream specified"); - Assert.notNull(charset, "No Charset specified"); - try { - return baos.toString(charset.name()); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } - private static class NonClosingInputStream extends FilterInputStream { public NonClosingInputStream(InputStream in) { diff --git a/spring-core/src/main/java/org/springframework/util/StringUtils.java b/spring-core/src/main/java/org/springframework/util/StringUtils.java index 1d7c33e94a..f75cbcdedf 100644 --- a/spring-core/src/main/java/org/springframework/util/StringUtils.java +++ b/spring-core/src/main/java/org/springframework/util/StringUtils.java @@ -749,7 +749,7 @@ public abstract class StringUtils { } Assert.notNull(charset, "Charset must not be null"); - ByteArrayOutputStream bos = new ByteArrayOutputStream(length); + ByteArrayOutputStream baos = new ByteArrayOutputStream(length); boolean changed = false; for (int i = 0; i < length; i++) { int ch = source.charAt(i); @@ -762,7 +762,7 @@ public abstract class StringUtils { if (u == -1 || l == -1) { throw new IllegalArgumentException("Invalid encoded sequence \"" + source.substring(i) + "\""); } - bos.write((char) ((u << 4) + l)); + baos.write((char) ((u << 4) + l)); i += 2; changed = true; } @@ -771,10 +771,10 @@ public abstract class StringUtils { } } else { - bos.write(ch); + baos.write(ch); } } - return changed ? StreamUtils.baosToString(bos, charset) : source; + return (changed ? StreamUtils.copyToString(baos, charset) : source); } /** diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompDecoder.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompDecoder.java index 1fb95f3e92..ae273e5616 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompDecoder.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompDecoder.java @@ -217,7 +217,7 @@ public class StompDecoder { while (byteBuffer.remaining() > 0 && !tryConsumeEndOfLine(byteBuffer)) { command.write(byteBuffer.get()); } - return StreamUtils.baosToString(command, StandardCharsets.UTF_8); + return StreamUtils.copyToString(command, StandardCharsets.UTF_8); } private void readHeaders(ByteBuffer byteBuffer, StompHeaderAccessor headerAccessor) { @@ -232,7 +232,7 @@ public class StompDecoder { headerStream.write(byteBuffer.get()); } if (headerStream.size() > 0 && headerComplete) { - String header = StreamUtils.baosToString(headerStream, StandardCharsets.UTF_8); + String header = StreamUtils.copyToString(headerStream, StandardCharsets.UTF_8); int colonIndex = header.indexOf(':'); if (colonIndex <= 0) { if (byteBuffer.remaining() > 0) { diff --git a/spring-test/src/main/java/org/springframework/mock/http/MockHttpOutputMessage.java b/spring-test/src/main/java/org/springframework/mock/http/MockHttpOutputMessage.java index 59426bb0ea..4926274996 100644 --- a/spring-test/src/main/java/org/springframework/mock/http/MockHttpOutputMessage.java +++ b/spring-test/src/main/java/org/springframework/mock/http/MockHttpOutputMessage.java @@ -76,7 +76,7 @@ public class MockHttpOutputMessage implements HttpOutputMessage { * @param charset the charset to use to turn the body content to a String */ public String getBodyAsString(Charset charset) { - return StreamUtils.baosToString(this.body, charset); + return StreamUtils.copyToString(this.body, charset); } } diff --git a/spring-web/src/main/java/org/springframework/http/ContentDisposition.java b/spring-web/src/main/java/org/springframework/http/ContentDisposition.java index a0f6e08b60..c87efa771c 100644 --- a/spring-web/src/main/java/org/springframework/http/ContentDisposition.java +++ b/spring-web/src/main/java/org/springframework/http/ContentDisposition.java @@ -398,18 +398,18 @@ public final class ContentDisposition { Assert.notNull(filename, "'input' String` should not be null"); Assert.notNull(charset, "'charset' should not be null"); byte[] value = filename.getBytes(charset); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); int index = 0; while (index < value.length) { byte b = value[index]; if (isRFC5987AttrChar(b)) { - bos.write((char) b); + baos.write((char) b); index++; } else if (b == '%' && index < value.length - 2) { char[] array = new char[]{(char) value[index + 1], (char) value[index + 2]}; try { - bos.write(Integer.parseInt(String.valueOf(array), 16)); + baos.write(Integer.parseInt(String.valueOf(array), 16)); } catch (NumberFormatException ex) { throw new IllegalArgumentException(INVALID_HEADER_FIELD_PARAMETER_FORMAT, ex); @@ -420,7 +420,7 @@ public final class ContentDisposition { throw new IllegalArgumentException(INVALID_HEADER_FIELD_PARAMETER_FORMAT); } } - return StreamUtils.baosToString(bos, charset); + return StreamUtils.copyToString(baos, charset); } private static boolean isRFC5987AttrChar(byte c) { diff --git a/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java b/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java index 3f26e357aa..6a28854714 100644 --- a/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java +++ b/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java @@ -347,20 +347,20 @@ final class HierarchicalUriComponents extends UriComponents { return source; } - ByteArrayOutputStream bos = new ByteArrayOutputStream(bytes.length); + ByteArrayOutputStream baos = new ByteArrayOutputStream(bytes.length); for (byte b : bytes) { if (type.isAllowed(b)) { - bos.write(b); + baos.write(b); } else { - bos.write('%'); + baos.write('%'); char hex1 = Character.toUpperCase(Character.forDigit((b >> 4) & 0xF, 16)); char hex2 = Character.toUpperCase(Character.forDigit(b & 0xF, 16)); - bos.write(hex1); - bos.write(hex2); + baos.write(hex1); + baos.write(hex2); } } - return StreamUtils.baosToString(bos, charset); + return StreamUtils.copyToString(baos, charset); } private Type getHostType() { diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/JettyXhrTransport.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/JettyXhrTransport.java index 8a5edb284b..772e6c0295 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/JettyXhrTransport.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/JettyXhrTransport.java @@ -248,7 +248,7 @@ public class JettyXhrTransport extends AbstractXhrTransport implements Lifecycle } private void handleFrame() { - String content = StreamUtils.baosToString(this.outputStream, SockJsFrame.CHARSET); + String content = StreamUtils.copyToString(this.outputStream, SockJsFrame.CHARSET); this.outputStream.reset(); if (logger.isTraceEnabled()) { logger.trace("XHR content received: " + content); diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/UndertowXhrTransport.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/UndertowXhrTransport.java index 8a22f45b46..6d2ace3441 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/UndertowXhrTransport.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/UndertowXhrTransport.java @@ -38,7 +38,6 @@ import io.undertow.util.HeaderMap; import io.undertow.util.HttpString; import io.undertow.util.Methods; import io.undertow.util.StringReadChannelListener; -import org.springframework.util.StreamUtils; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import org.xnio.IoUtils; @@ -54,6 +53,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.lang.Nullable; import org.springframework.util.Assert; +import org.springframework.util.StreamUtils; import org.springframework.util.StringUtils; import org.springframework.util.concurrent.SettableListenableFuture; import org.springframework.web.client.HttpServerErrorException; @@ -439,7 +439,7 @@ public class UndertowXhrTransport extends AbstractXhrTransport { } private void handleFrame() { - String content = StreamUtils.baosToString(this.outputStream, SockJsFrame.CHARSET); + String content = StreamUtils.copyToString(this.outputStream, SockJsFrame.CHARSET); this.outputStream.reset(); if (logger.isTraceEnabled()) { logger.trace("XHR content received: " + content);