Skip to content

Commit b4ae8a7

Browse files
committed
Cleanups
1 parent 23cf86e commit b4ae8a7

7 files changed

Lines changed: 96 additions & 172 deletions

File tree

.changes/next-release/feature-AWSSDKforJavav2-439f346.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
"type": "feature",
33
"category": "AWS SDK for Java v2",
44
"contributor": "",
5-
"description": "Optimized JSON marshalling performance for JSON RPC and REST JSON protocols."
6-
}
5+
"description": "Optimized JSON marshalling performance for JSON RPC, REST JSON and RPCv2 Cbor protocols."
6+
}

core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/ExposedByteArrayOutputStream.java

Lines changed: 0 additions & 51 deletions
This file was deleted.

core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/SdkByteArrayOutputStream.java

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717

1818
import java.io.ByteArrayInputStream;
1919
import java.io.ByteArrayOutputStream;
20+
import java.io.IOException;
2021
import java.io.InputStream;
22+
import java.io.OutputStream;
2123
import java.io.SequenceInputStream;
2224
import java.util.ArrayList;
2325
import java.util.Collections;
@@ -135,6 +137,38 @@ public byte[] toByteArray() {
135137
return result;
136138
}
137139

140+
/**
141+
* Resets this stream so that all currently accumulated output is discarded, including any
142+
* overflow chunks. After calling this method, the stream can be reused as if freshly constructed.
143+
*/
144+
@Override
145+
public void reset() {
146+
super.reset();
147+
overflowing = false;
148+
overflowChunks = null;
149+
overflowChunkOffset = 0;
150+
overflowTotalBytes = 0;
151+
}
152+
153+
/**
154+
* Writes the complete contents of this stream to the specified output stream, including
155+
* any overflow chunks.
156+
*/
157+
@Override
158+
public void writeTo(OutputStream out) throws IOException {
159+
if (!overflowing) {
160+
super.writeTo(out);
161+
return;
162+
}
163+
// Write base buffer
164+
out.write(buf, 0, count);
165+
// Write overflow chunks
166+
for (int i = 0; i < overflowChunks.size(); i++) {
167+
int len = (i < overflowChunks.size() - 1) ? overflowChunks.get(i).length : overflowChunkOffset;
168+
out.write(overflowChunks.get(i), 0, len);
169+
}
170+
}
171+
138172
/**
139173
* Returns a {@link ContentStreamProvider} that streams directly from the internal buffers
140174
* without creating a contiguous copy. For small payloads this wraps the single base buffer;
@@ -143,7 +177,7 @@ public byte[] toByteArray() {
143177
*/
144178
ContentStreamProvider contentStreamProvider() {
145179
if (!overflowing) {
146-
// Small payload: single buffer, wrap directly (same as ExposedByteArrayOutputStream)
180+
// Small payload: single buffer, wrap directly
147181
byte[] b = buf;
148182
int c = count;
149183
return () -> new ByteArrayInputStream(b, 0, c);

core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/StructuredJsonGenerator.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@
1515

1616
package software.amazon.awssdk.protocols.json;
1717

18+
import java.io.ByteArrayInputStream;
1819
import java.math.BigDecimal;
1920
import java.math.BigInteger;
2021
import java.nio.ByteBuffer;
2122
import java.time.Instant;
2223
import software.amazon.awssdk.annotations.SdkProtectedApi;
24+
import software.amazon.awssdk.http.ContentStreamProvider;
2325

2426
/**
2527
* Interface for generating a JSON
@@ -102,6 +104,11 @@ public StructuredJsonGenerator writeValue(ByteBuffer bytes) {
102104
return this;
103105
}
104106

107+
@Override
108+
public StructuredJsonGenerator writeBinaryValue(byte[] bytes) {
109+
return this;
110+
}
111+
105112
@Override
106113
public StructuredJsonGenerator writeValue(Instant instant) {
107114
return this;
@@ -193,4 +200,28 @@ default StructuredJsonGenerator writeBinaryValue(byte[] bytes) {
193200
*/
194201
@Deprecated
195202
String getContentType();
203+
204+
/**
205+
* Returns the size of the generated content in bytes without copying. The default
206+
* implementation falls back to {@link #getBytes()}.length.
207+
*/
208+
default int contentSize() {
209+
byte[] bytes = getBytes();
210+
return bytes == null ? 0 : bytes.length;
211+
}
212+
213+
/**
214+
* Returns a {@link ContentStreamProvider} that streams the generated content. The default
215+
* implementation wraps the result of {@link #getBytes()} in a {@code ByteArrayInputStream}.
216+
* Implementations may override this to stream directly from internal buffers without copying.
217+
*
218+
* @return a content stream provider, or {@code null} if {@link #getBytes()} returns null
219+
*/
220+
default ContentStreamProvider contentStreamProvider() {
221+
byte[] bytes = getBytes();
222+
if (bytes == null) {
223+
return null;
224+
}
225+
return () -> new ByteArrayInputStream(bytes);
226+
}
196227
}

core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/JsonProtocolMarshaller.java

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@
5353
import software.amazon.awssdk.protocols.json.AwsJsonProtocol;
5454
import software.amazon.awssdk.protocols.json.AwsJsonProtocolMetadata;
5555
import software.amazon.awssdk.protocols.json.BaseAwsJsonProtocolFactory;
56-
import software.amazon.awssdk.protocols.json.SdkJsonGenerator;
5756
import software.amazon.awssdk.protocols.json.StructuredJsonGenerator;
5857
import software.amazon.awssdk.protocols.json.internal.ProtocolFact;
5958

@@ -70,6 +69,8 @@ public class JsonProtocolMarshaller implements ProtocolMarshaller<SdkHttpFullReq
7069

7170
// Caches the resolved marshaller for non-PAYLOAD fields, keyed by SdkField identity.
7271
// SdkField instances are static final per generated model class, so identity-based lookup is correct.
72+
// The cache is effectively bounded by the total number of non-payload SdkField instances across all
73+
// loaded service models — each SdkField is inserted at most once, and no eviction is needed.
7374
// ConcurrentHashMap is used for thread safety; the one-time put per SdkField is negligible.
7475
private static final ConcurrentHashMap<SdkField<?>, JsonMarshaller<Object>> MARSHALLER_CACHE =
7576
new ConcurrentHashMap<>();
@@ -290,25 +291,13 @@ private SdkHttpFullRequest finishMarshalling() {
290291
jsonGenerator.writeEndObject();
291292
}
292293

293-
if (jsonGenerator instanceof SdkJsonGenerator) {
294-
// Optimized path: stream directly from chunked buffers, avoiding a single
295-
// contiguous byte[] allocation that can cause G1GC humongous allocations.
296-
SdkJsonGenerator sdkGenerator = (SdkJsonGenerator) jsonGenerator;
297-
ContentStreamProvider contentProvider = sdkGenerator.contentStreamProvider();
294+
ContentStreamProvider contentProvider = jsonGenerator.contentStreamProvider();
295+
if (contentProvider != null) {
298296
request.contentStreamProvider(contentProvider);
299-
int contentSize = sdkGenerator.contentSize();
297+
int contentSize = jsonGenerator.contentSize();
300298
if (contentSize > 0) {
301299
request.putHeader(CONTENT_LENGTH, Integer.toString(contentSize));
302300
}
303-
} else {
304-
byte[] content = jsonGenerator.getBytes();
305-
306-
if (content != null) {
307-
request.contentStreamProvider(() -> new ByteArrayInputStream(content));
308-
if (content.length > 0) {
309-
request.putHeader(CONTENT_LENGTH, Integer.toString(content.length));
310-
}
311-
}
312301
}
313302
}
314303

core/protocols/aws-json-protocol/src/test/java/software/amazon/awssdk/protocols/json/ExposedByteArrayOutputStreamTest.java

Lines changed: 0 additions & 79 deletions
This file was deleted.

0 commit comments

Comments
 (0)