Skip to content

Commit dd7f54c

Browse files
committed
Revised ResizableByteArrayOutputStream as an actual subclass of ByteArrayOutputStream, and consistently applied appropriate ByteArrayOutputStream initial capacities across the codebase
Issue: SPR-11594
1 parent 05213c6 commit dd7f54c

File tree

23 files changed

+160
-228
lines changed

23 files changed

+160
-228
lines changed

spring-core/src/main/java/org/springframework/core/convert/support/PropertiesToStringConverter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -34,7 +34,7 @@ final class PropertiesToStringConverter implements Converter<Properties, String>
3434
@Override
3535
public String convert(Properties source) {
3636
try {
37-
ByteArrayOutputStream os = new ByteArrayOutputStream();
37+
ByteArrayOutputStream os = new ByteArrayOutputStream(256);
3838
source.store(os, null);
3939
return os.toString("ISO-8859-1");
4040
}

spring-core/src/main/java/org/springframework/core/serializer/support/SerializingConverter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -57,7 +57,7 @@ public SerializingConverter(Serializer<Object> serializer) {
5757
*/
5858
@Override
5959
public byte[] convert(Object source) {
60-
ByteArrayOutputStream byteStream = new ByteArrayOutputStream(128);
60+
ByteArrayOutputStream byteStream = new ByteArrayOutputStream(256);
6161
try {
6262
this.serializer.serialize(source, byteStream);
6363
return byteStream.toByteArray();

spring-core/src/main/java/org/springframework/core/style/ToStringCreator.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -36,11 +36,11 @@ public class ToStringCreator {
3636
new DefaultToStringStyler(StylerUtils.DEFAULT_VALUE_STYLER);
3737

3838

39-
private StringBuilder buffer = new StringBuilder(512);
39+
private final StringBuilder buffer = new StringBuilder(256);
4040

41-
private ToStringStyler styler;
41+
private final ToStringStyler styler;
4242

43-
private Object object;
43+
private final Object object;
4444

4545
private boolean styledFirstField;
4646

spring-core/src/main/java/org/springframework/util/ResizableByteArrayOutputStream.java

Lines changed: 37 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -13,143 +13,79 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16+
1617
package org.springframework.util;
1718

18-
import java.io.IOException;
19-
import java.io.OutputStream;
19+
import java.io.ByteArrayOutputStream;
2020

2121
/**
22-
* A variation of {@link java.io.ByteArrayOutputStream} that:
22+
* An extension of {@link java.io.ByteArrayOutputStream} that:
2323
* <ul>
24-
* <li>has public {@link org.springframework.util.ResizableByteArrayOutputStream#grow(int)} and
25-
* {@link org.springframework.util.ResizableByteArrayOutputStream#resize(int)} methods to get more control
26-
* over the the size of the internal buffer</li>
27-
* <li>does not synchronize on buffer access - so this class should not be used if concurrent access
28-
* to the buffer is expected</li>
24+
* <li>has public {@link org.springframework.util.ResizableByteArrayOutputStream#grow(int)}
25+
* and {@link org.springframework.util.ResizableByteArrayOutputStream#resize(int)} methods
26+
* to get more control over the the size of the internal buffer</li>
27+
* <li>has a higher initial capacity (256) by default</li>
2928
* </ul>
3029
*
3130
* @author Brian Clozel
31+
* @author Juergen Hoeller
3232
* @since 4.0
3333
*/
34-
public class ResizableByteArrayOutputStream extends OutputStream {
35-
36-
private static final int INITIAL_BUFFER_SIZE = 32;
34+
public class ResizableByteArrayOutputStream extends ByteArrayOutputStream {
3735

38-
protected byte[] buffer;
36+
private static final int DEFAULT_INITIAL_CAPACITY = 256;
3937

40-
protected int count;
4138

4239
/**
43-
* Create a new <code>ByteArrayOutputStream</code> with the default buffer size of 32 bytes.
40+
* Create a new <code>ResizableByteArrayOutputStream</code>
41+
* with the default initial capacity of 128 bytes.
4442
*/
4543
public ResizableByteArrayOutputStream() {
46-
this(INITIAL_BUFFER_SIZE);
47-
}
48-
49-
/**
50-
* Create a new <code>ByteArrayOutputStream</code> with a specified initial buffer size.
51-
*
52-
* @param size The initial buffer size in bytes
53-
*/
54-
public ResizableByteArrayOutputStream(int size) {
55-
buffer = new byte[size];
56-
count = 0;
57-
}
58-
59-
/**
60-
* Return the size of the internal buffer.
61-
*/
62-
public int size() {
63-
return buffer.length;
44+
super(DEFAULT_INITIAL_CAPACITY);
6445
}
6546

6647
/**
67-
* Return the number of bytes that have been written to the buffer so far.
48+
* Create a new <code>ResizableByteArrayOutputStream</code>
49+
* with the specified initial capacity.
50+
* @param initialCapacity the initial buffer size in bytes
6851
*/
69-
public int count() {
70-
return count;
52+
public ResizableByteArrayOutputStream(int initialCapacity) {
53+
super(initialCapacity);
7154
}
7255

73-
/**
74-
* Discard all bytes written to the internal buffer by setting the <code>count</code> variable to 0.
75-
*/
76-
public void reset() {
77-
count = 0;
78-
}
7956

8057
/**
81-
* Grow the internal buffer size
82-
* @param add number of bytes to add to the current buffer size
58+
* Resize the internal buffer size to a specified capacity.
59+
* @param targetCapacity the desired size of the buffer
60+
* @throws IllegalArgumentException if the given capacity is smaller than
61+
* the actual size of the content stored in the buffer already
8362
* @see ResizableByteArrayOutputStream#size()
8463
*/
85-
public void grow(int add) {
86-
if (count + add > buffer.length) {
87-
int newlen = Math.max(buffer.length * 2, count + add);
88-
resize(newlen);
89-
}
64+
public synchronized void resize(int targetCapacity) {
65+
Assert.isTrue(targetCapacity >= this.count, "New capacity must not be smaller than current size");
66+
byte[] resizedBuffer = new byte[targetCapacity];
67+
System.arraycopy(this.buf, 0, resizedBuffer, 0, this.count);
68+
this.buf = resizedBuffer;
9069
}
9170

9271
/**
93-
* Resize the internal buffer size to a specified value
94-
* @param size the size of the buffer
95-
* @throws java.lang.IllegalArgumentException if the given size is
96-
* smaller than the actual size of the content stored in the buffer
72+
* Grow the internal buffer size.
73+
* @param additionalCapacity the number of bytes to add to the current buffer size
9774
* @see ResizableByteArrayOutputStream#size()
9875
*/
99-
public void resize(int size) {
100-
Assert.isTrue(size >= count);
101-
102-
byte[] newbuf = new byte[size];
103-
System.arraycopy(buffer, 0, newbuf, 0, count);
104-
buffer = newbuf;
105-
}
106-
107-
/**
108-
* Write the specified byte into the internal buffer, thus incrementing the
109-
* {{@link org.springframework.util.ResizableByteArrayOutputStream#count()}}
110-
* @param oneByte the byte to be written in the buffer
111-
* @see ResizableByteArrayOutputStream#count()
112-
*/
113-
public void write(int oneByte) {
114-
grow(1);
115-
buffer[count++] = (byte) oneByte;
116-
}
117-
118-
/**
119-
* Write <code>add</code> bytes from the passed in array
120-
* <code>inBuffer</code> starting at index <code>offset</code> into the
121-
* internal buffer.
122-
*
123-
* @param inBuffer The byte array to write data from
124-
* @param offset The index into the buffer to start writing data from
125-
* @param add The number of bytes to write
126-
* @see ResizableByteArrayOutputStream#count()
127-
*/
128-
public void write(byte[] inBuffer, int offset, int add) {
129-
if (add >= 0) {
130-
grow(add);
76+
public synchronized void grow(int additionalCapacity) {
77+
Assert.isTrue(additionalCapacity >= 0, "Additional capacity must be 0 or higher");
78+
if (this.count + additionalCapacity > this.buf.length) {
79+
int newCapacity = Math.max(this.buf.length * 2, this.count + additionalCapacity);
80+
resize(newCapacity);
13181
}
132-
System.arraycopy(inBuffer, offset, buffer, count, add);
133-
count += add;
134-
}
135-
136-
/**
137-
* Write all bytes that have been written to the specified <code>OutputStream</code>.
138-
*
139-
* @param out The <code>OutputStream</code> to write to
140-
* @exception IOException If an error occurs
141-
*/
142-
public void writeTo(OutputStream out) throws IOException {
143-
out.write(buffer, 0, count);
14482
}
14583

14684
/**
147-
* Return a byte array containing the bytes that have been written to this stream so far.
85+
* Return the current size of this stream's internal buffer.
14886
*/
149-
public byte[] toByteArray() {
150-
byte[] ret = new byte[count];
151-
System.arraycopy(buffer, 0, ret, 0, count);
152-
return ret;
87+
public synchronized int capacity() {
88+
return this.buf.length;
15389
}
15490

15591
}

spring-core/src/main/java/org/springframework/util/SerializationUtils.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2010 the original author or authors.
2+
* Copyright 2002-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -39,7 +39,7 @@ public static byte[] serialize(Object object) {
3939
if (object == null) {
4040
return null;
4141
}
42-
ByteArrayOutputStream baos = new ByteArrayOutputStream();
42+
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
4343
try {
4444
ObjectOutputStream oos = new ObjectOutputStream(baos);
4545
oos.writeObject(object);

spring-core/src/test/java/org/springframework/util/ResizableByteArrayOutputStreamTests.java

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16+
1617
package org.springframework.util;
1718

1819
import org.junit.Before;
@@ -22,56 +23,56 @@
2223

2324
/**
2425
* @author Brian Clozel
26+
* @author Juergen Hoeller
2527
*/
2628
public class ResizableByteArrayOutputStreamTests {
2729

28-
private ResizableByteArrayOutputStream baos;
30+
private static final int INITIAL_CAPACITY = 256;
2931

30-
private String helloString;
32+
private ResizableByteArrayOutputStream baos;
3133

3234
private byte[] helloBytes;
3335

34-
private static final int INITIAL_SIZE = 32;
3536

3637
@Before
3738
public void setUp() throws Exception {
38-
this.baos = new ResizableByteArrayOutputStream(INITIAL_SIZE);
39-
this.helloString = "Hello World";
40-
this.helloBytes = helloString.getBytes("UTF-8");
39+
this.baos = new ResizableByteArrayOutputStream(INITIAL_CAPACITY);
40+
this.helloBytes = "Hello World".getBytes("UTF-8");
4141
}
4242

43+
4344
@Test
4445
public void resize() throws Exception {
45-
assertEquals(INITIAL_SIZE, this.baos.buffer.length);
46+
assertEquals(INITIAL_CAPACITY, this.baos.capacity());
4647
this.baos.write(helloBytes);
4748
int size = 64;
4849
this.baos.resize(size);
49-
assertEquals(size, this.baos.buffer.length);
50-
assertByteArrayEqualsString(helloString, this.baos);
50+
assertEquals(size, this.baos.capacity());
51+
assertByteArrayEqualsString(this.baos);
5152
}
5253

5354
@Test
5455
public void autoGrow() {
55-
assertEquals(INITIAL_SIZE, this.baos.buffer.length);
56-
for(int i= 0; i < 33; i++) {
56+
assertEquals(INITIAL_CAPACITY, this.baos.capacity());
57+
for(int i = 0; i < 129; i++) {
5758
this.baos.write(0);
5859
}
59-
assertEquals(64, this.baos.buffer.length);
60+
assertEquals(256, this.baos.capacity());
6061
}
6162

6263
@Test
6364
public void grow() throws Exception {
64-
assertEquals(INITIAL_SIZE, this.baos.buffer.length);
65+
assertEquals(INITIAL_CAPACITY, this.baos.capacity());
6566
this.baos.write(helloBytes);
66-
this.baos.grow(100);
67-
assertEquals(this.helloString.length() + 100, this.baos.buffer.length);
68-
assertByteArrayEqualsString(helloString, this.baos);
67+
this.baos.grow(1000);
68+
assertEquals(this.helloBytes.length + 1000, this.baos.capacity());
69+
assertByteArrayEqualsString(this.baos);
6970
}
7071

7172
@Test
7273
public void write() throws Exception{
7374
this.baos.write(helloBytes);
74-
assertByteArrayEqualsString(helloString, this.baos);
75+
assertByteArrayEqualsString(this.baos);
7576
}
7677

7778
@Test(expected = IllegalArgumentException.class)
@@ -80,9 +81,9 @@ public void failResize() throws Exception{
8081
this.baos.resize(5);
8182
}
8283

83-
private void assertByteArrayEqualsString(String expected, ResizableByteArrayOutputStream actual) {
84-
String actualString = new String(actual.buffer, 0, actual.count());
85-
assertEquals(expected, actualString);
84+
85+
private void assertByteArrayEqualsString(ResizableByteArrayOutputStream actual) {
86+
assertArrayEquals(helloBytes, actual.toByteArray());
8687
}
8788

8889
}

spring-jms/src/main/java/org/springframework/jms/support/converter/MappingJackson2MessageConverter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -218,7 +218,7 @@ protected TextMessage mapToTextMessage(Object object, Session session, ObjectMap
218218
protected BytesMessage mapToBytesMessage(Object object, Session session, ObjectMapper objectMapper)
219219
throws JMSException, IOException {
220220

221-
ByteArrayOutputStream bos = new ByteArrayOutputStream();
221+
ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
222222
OutputStreamWriter writer = new OutputStreamWriter(bos, this.encoding);
223223
objectMapper.writeValue(writer, object);
224224

spring-jms/src/main/java/org/springframework/jms/support/converter/MappingJacksonMessageConverter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -221,7 +221,7 @@ protected TextMessage mapToTextMessage(Object object, Session session, ObjectMap
221221
protected BytesMessage mapToBytesMessage(Object object, Session session, ObjectMapper objectMapper)
222222
throws JMSException, IOException {
223223

224-
ByteArrayOutputStream bos = new ByteArrayOutputStream();
224+
ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
225225
OutputStreamWriter writer = new OutputStreamWriter(bos, this.encoding);
226226
objectMapper.writeValue(writer, object);
227227

spring-jms/src/main/java/org/springframework/jms/support/converter/MarshallingMessageConverter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -231,7 +231,7 @@ protected TextMessage marshalToTextMessage(Object object, Session session, Marsh
231231
protected BytesMessage marshalToBytesMessage(Object object, Session session, Marshaller marshaller)
232232
throws JMSException, IOException, XmlMappingException {
233233

234-
ByteArrayOutputStream bos = new ByteArrayOutputStream();
234+
ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
235235
StreamResult streamResult = new StreamResult(bos);
236236
marshaller.marshal(object, streamResult);
237237
BytesMessage message = session.createBytesMessage();

0 commit comments

Comments
 (0)