Skip to content

Commit aad53ed

Browse files
authored
Merge pull request #1569 from dagnir/gh1534
Add RequestBody.fromRemainingByteBuffer()
2 parents 4fc588c + 2cd1664 commit aad53ed

File tree

5 files changed

+105
-1
lines changed

5 files changed

+105
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"type": "feature",
3+
"category": "AWS SDK for Java v2",
4+
"description": "Add `RequestBody.fromRemainingByteBuffer(ByteBuffer)` that copies only the remaining readable bytes of the buffer. See [#1534](https://github.com/aws/aws-sdk-java-v2/issues/1534)"
5+
}

core/sdk-core/src/main/java/software/amazon/awssdk/core/sync/RequestBody.java

+15
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,9 @@ public static RequestBody fromBytes(byte[] bytes) {
161161
/**
162162
* Creates a {@link RequestBody} from a {@link ByteBuffer}. Buffer contents are copied so any modifications
163163
* made to the original {@link ByteBuffer} are not reflected in the {@link RequestBody}.
164+
* <p>
165+
* <b>NOTE:</b> This method always copies the entire contents of the buffer, ignoring the current read position. Use
166+
* {@link #fromRemainingByteBuffer(ByteBuffer)} if you need it to copy only the remaining readable bytes.
164167
*
165168
* @param byteBuffer ByteBuffer to send to the service.
166169
* @return RequestBody instance.
@@ -169,6 +172,18 @@ public static RequestBody fromByteBuffer(ByteBuffer byteBuffer) {
169172
return fromBytesDirect(BinaryUtils.copyAllBytesFrom(byteBuffer));
170173
}
171174

175+
/**
176+
* Creates a {@link RequestBody} from the remaining readable bytes from a {@link ByteBuffer}. Unlike
177+
* {@link #fromByteBuffer(ByteBuffer)}, this method respects the current read position of the buffer and reads only
178+
* the remaining bytes. The buffer is copied before reading so no changes are made to original buffer.
179+
*
180+
* @param byteBuffer ByteBuffer to send to the service.
181+
* @return RequestBody instance.
182+
*/
183+
public static RequestBody fromRemainingByteBuffer(ByteBuffer byteBuffer) {
184+
return fromBytesDirect(BinaryUtils.copyRemainingBytesFrom(byteBuffer));
185+
}
186+
172187
/**
173188
* Creates a {@link RequestBody} with no content.
174189
*

core/sdk-core/src/test/java/software/amazon/awssdk/core/sync/RequestBodyTest.java

+19-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import com.google.common.jimfs.Configuration;
2121
import com.google.common.jimfs.Jimfs;
2222
import java.io.File;
23-
import java.io.FileInputStream;
2423
import java.io.FileWriter;
2524
import java.io.IOException;
2625
import java.io.InputStream;
@@ -104,4 +103,23 @@ public void emptyBytesConstructorHasCorrectContentType() {
104103
RequestBody requestBody = RequestBody.empty();
105104
assertThat(requestBody.contentType()).isEqualTo(Mimetype.MIMETYPE_OCTET_STREAM);
106105
}
106+
107+
@Test
108+
public void remainingByteBufferConstructorOnlyRemainingBytesCopied() throws IOException {
109+
ByteBuffer bb = ByteBuffer.allocate(4);
110+
bb.put(new byte[]{1, 2, 3, 4});
111+
bb.flip();
112+
113+
bb.get();
114+
bb.get();
115+
116+
int originalRemaining = bb.remaining();
117+
118+
RequestBody requestBody = RequestBody.fromRemainingByteBuffer(bb);
119+
120+
assertThat(requestBody.contentLength()).isEqualTo(originalRemaining);
121+
122+
byte[] requestBodyBytes = IoUtils.toByteArray(requestBody.contentStreamProvider().newStream());
123+
assertThat(ByteBuffer.wrap(requestBodyBytes)).isEqualTo(bb);
124+
}
107125
}

utils/src/main/java/software/amazon/awssdk/utils/BinaryUtils.java

+24
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
*/
2929
@SdkProtectedApi
3030
public final class BinaryUtils {
31+
private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
3132

3233
private BinaryUtils() {
3334
}
@@ -150,6 +151,29 @@ public static byte[] copyAllBytesFrom(ByteBuffer bb) {
150151
return dst;
151152
}
152153

154+
public static byte[] copyRemainingBytesFrom(ByteBuffer bb) {
155+
if (bb == null) {
156+
return null;
157+
}
158+
159+
if (!bb.hasRemaining()) {
160+
return EMPTY_BYTE_ARRAY;
161+
}
162+
163+
if (bb.hasArray()) {
164+
int endIdx = bb.arrayOffset() + bb.limit();
165+
int startIdx = endIdx - bb.remaining();
166+
return Arrays.copyOfRange(bb.array(), startIdx, endIdx);
167+
}
168+
169+
ByteBuffer copy = bb.asReadOnlyBuffer();
170+
171+
byte[] dst = new byte[copy.remaining()];
172+
copy.get(dst);
173+
174+
return dst;
175+
}
176+
153177
/**
154178
* Returns a copy of the bytes from the given <code>ByteBuffer</code>,
155179
* ranging from the the buffer's current position to the buffer's limit; or

utils/src/test/java/software/amazon/awssdk/utils/BinaryUtilsTest.java

+42
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
package software.amazon.awssdk.utils;
1717

18+
import static org.assertj.core.api.Assertions.assertThat;
1819
import static org.junit.Assert.assertEquals;
1920
import static org.junit.Assert.assertFalse;
2021
import static org.junit.Assert.assertNull;
@@ -159,4 +160,45 @@ public void testCopyBytesFrom_DirectByteBuffer_Idempotent() {
159160
assertTrue(partial1.length == 3);
160161
assertTrue(Arrays.equals(new byte[] {2, 3, 4}, partial1));
161162
}
163+
164+
@Test
165+
public void testCopyRemainingBytesFrom_nullBuffer() {
166+
assertThat(BinaryUtils.copyRemainingBytesFrom(null)).isNull();
167+
}
168+
169+
@Test
170+
public void testCopyRemainingBytesFrom_noRemainingBytes() {
171+
ByteBuffer bb = ByteBuffer.allocate(1);
172+
bb.put(new byte[]{1});
173+
bb.flip();
174+
175+
bb.get();
176+
177+
assertThat(BinaryUtils.copyRemainingBytesFrom(bb)).hasSize(0);
178+
}
179+
180+
@Test
181+
public void testCopyRemainingBytesFrom_fullBuffer() {
182+
ByteBuffer bb = ByteBuffer.allocate(4);
183+
bb.put(new byte[]{1, 2, 3, 4});
184+
bb.flip();
185+
186+
byte[] copy = BinaryUtils.copyRemainingBytesFrom(bb);
187+
assertThat(bb).isEqualTo(ByteBuffer.wrap(copy));
188+
assertThat(copy).hasSize(4);
189+
}
190+
191+
@Test
192+
public void testCopyRemainingBytesFrom_partiallyReadBuffer() {
193+
ByteBuffer bb = ByteBuffer.allocate(4);
194+
bb.put(new byte[]{1, 2, 3, 4});
195+
bb.flip();
196+
197+
bb.get();
198+
bb.get();
199+
200+
byte[] copy = BinaryUtils.copyRemainingBytesFrom(bb);
201+
assertThat(bb).isEqualTo(ByteBuffer.wrap(copy));
202+
assertThat(copy).hasSize(2);
203+
}
162204
}

0 commit comments

Comments
 (0)