diff --git a/spring-context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCache.java b/spring-context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCache.java index 6b3906fa88d..8a649122194 100644 --- a/spring-context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCache.java +++ b/spring-context/src/main/java/org/springframework/cache/concurrent/ConcurrentMapCache.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. @@ -202,15 +202,10 @@ public class ConcurrentMapCache extends AbstractValueAdaptingCache { } } - private Object serializeValue(SerializationDelegate serialization, Object storeValue) throws IOException { + private static Object serializeValue(SerializationDelegate serialization, Object storeValue) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); - try { - serialization.serialize(storeValue, out); - return out.toByteArray(); - } - finally { - out.close(); - } + serialization.serialize(storeValue, out); + return out.toByteArray(); } @Override @@ -229,14 +224,9 @@ public class ConcurrentMapCache extends AbstractValueAdaptingCache { } - private Object deserializeValue(SerializationDelegate serialization, Object storeValue) throws IOException { + private static Object deserializeValue(SerializationDelegate serialization, Object storeValue) throws IOException { ByteArrayInputStream in = new ByteArrayInputStream((byte[]) storeValue); - try { - return serialization.deserialize(in); - } - finally { - in.close(); - } + return serialization.deserialize(in); } } 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 9ada13667cb..bf0f708f6fb 100644 --- a/spring-core/src/main/java/org/springframework/util/StreamUtils.java +++ b/spring-core/src/main/java/org/springframework/util/StreamUtils.java @@ -25,6 +25,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; +import java.io.UnsupportedEncodingException; import java.io.Writer; import java.nio.charset.Charset; @@ -238,6 +239,24 @@ 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 { 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 fbdc825adaf..1d7c33e94ab 100644 --- a/spring-core/src/main/java/org/springframework/util/StringUtils.java +++ b/spring-core/src/main/java/org/springframework/util/StringUtils.java @@ -774,7 +774,7 @@ public abstract class StringUtils { bos.write(ch); } } - return (changed ? new String(bos.toByteArray(), charset) : source); + return changed ? StreamUtils.baosToString(bos, charset) : source; } /** diff --git a/spring-core/src/testFixtures/java/org/springframework/core/testfixture/io/SerializationTestUtils.java b/spring-core/src/testFixtures/java/org/springframework/core/testfixture/io/SerializationTestUtils.java index 8958435aa21..ebeec7bf6a3 100644 --- a/spring-core/src/testFixtures/java/org/springframework/core/testfixture/io/SerializationTestUtils.java +++ b/spring-core/src/testFixtures/java/org/springframework/core/testfixture/io/SerializationTestUtils.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. @@ -55,7 +55,6 @@ public class SerializationTestUtils { oos.writeObject(o); oos.flush(); } - baos.flush(); byte[] bytes = baos.toByteArray(); ByteArrayInputStream is = new ByteArrayInputStream(bytes); 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 3c1b82ba8a7..1fb95f3e921 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 @@ -33,6 +33,7 @@ import org.springframework.messaging.support.MessageHeaderInitializer; import org.springframework.messaging.support.NativeMessageHeaderAccessor; import org.springframework.util.InvalidMimeTypeException; import org.springframework.util.MultiValueMap; +import org.springframework.util.StreamUtils; /** * Decodes one or more STOMP frames contained in a {@link ByteBuffer}. @@ -216,7 +217,7 @@ public class StompDecoder { while (byteBuffer.remaining() > 0 && !tryConsumeEndOfLine(byteBuffer)) { command.write(byteBuffer.get()); } - return new String(command.toByteArray(), StandardCharsets.UTF_8); + return StreamUtils.baosToString(command, StandardCharsets.UTF_8); } private void readHeaders(ByteBuffer byteBuffer, StompHeaderAccessor headerAccessor) { @@ -231,7 +232,7 @@ public class StompDecoder { headerStream.write(byteBuffer.get()); } if (headerStream.size() > 0 && headerComplete) { - String header = new String(headerStream.toByteArray(), StandardCharsets.UTF_8); + String header = StreamUtils.baosToString(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 e9c5c3b94bb..59426bb0ea7 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 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. @@ -24,6 +24,7 @@ import java.nio.charset.StandardCharsets; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpOutputMessage; +import org.springframework.util.StreamUtils; /** * Mock implementation of {@link HttpOutputMessage}. @@ -75,8 +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) { - byte[] bytes = getBodyAsBytes(); - return new String(bytes, charset); + return StreamUtils.baosToString(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 c50ffc715a3..a0f6e08b60e 100644 --- a/spring-web/src/main/java/org/springframework/http/ContentDisposition.java +++ b/spring-web/src/main/java/org/springframework/http/ContentDisposition.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. @@ -27,6 +27,7 @@ import java.util.List; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; +import org.springframework.util.StreamUtils; import static java.nio.charset.StandardCharsets.ISO_8859_1; import static java.nio.charset.StandardCharsets.UTF_8; @@ -419,7 +420,7 @@ public final class ContentDisposition { throw new IllegalArgumentException(INVALID_HEADER_FIELD_PARAMETER_FORMAT); } } - return new String(bos.toByteArray(), charset); + return StreamUtils.baosToString(bos, 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 cd088e039db..3f26e357aa6 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 @@ -36,6 +36,7 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.util.ObjectUtils; +import org.springframework.util.StreamUtils; import org.springframework.util.StringUtils; /** @@ -359,7 +360,7 @@ final class HierarchicalUriComponents extends UriComponents { bos.write(hex2); } } - return new String(bos.toByteArray(), charset); + return StreamUtils.baosToString(bos, 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 940cad1a3fa..8a5edb284b8 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 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. @@ -35,6 +35,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.concurrent.SettableListenableFuture; import org.springframework.web.client.HttpServerErrorException; import org.springframework.web.socket.CloseStatus; @@ -247,14 +248,13 @@ public class JettyXhrTransport extends AbstractXhrTransport implements Lifecycle } private void handleFrame() { - byte[] bytes = this.outputStream.toByteArray(); + String content = StreamUtils.baosToString(this.outputStream, SockJsFrame.CHARSET); this.outputStream.reset(); - String content = new String(bytes, SockJsFrame.CHARSET); if (logger.isTraceEnabled()) { logger.trace("XHR content received: " + content); } if (!PRELUDE.equals(content)) { - this.sockJsSession.handleFrame(new String(bytes, SockJsFrame.CHARSET)); + this.sockJsSession.handleFrame(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 576d5e21407..8a22f45b46b 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 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. @@ -38,6 +38,7 @@ 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; @@ -405,8 +406,7 @@ public class UndertowXhrTransport extends AbstractXhrTransport { throw new SockJsException("Session closed.", this.session.getId(), null); } - PooledByteBuffer pooled = bufferPool.allocate(); - try { + try (PooledByteBuffer pooled = bufferPool.allocate()) { int r; do { ByteBuffer buffer = pooled.getBuffer(); @@ -436,20 +436,16 @@ public class UndertowXhrTransport extends AbstractXhrTransport { catch (IOException exc) { onFailure(exc); } - finally { - pooled.close(); - } } private void handleFrame() { - byte[] bytes = this.outputStream.toByteArray(); + String content = StreamUtils.baosToString(this.outputStream, SockJsFrame.CHARSET); this.outputStream.reset(); - String content = new String(bytes, SockJsFrame.CHARSET); if (logger.isTraceEnabled()) { logger.trace("XHR content received: " + content); } if (!PRELUDE.equals(content)) { - this.session.handleFrame(new String(bytes, SockJsFrame.CHARSET)); + this.session.handleFrame(content); } }