1313import java .time .Instant ;
1414import java .util .function .BiConsumer ;
1515import software .amazon .smithy .java .core .schema .Schema ;
16+ import software .amazon .smithy .java .core .schema .SerializableShape ;
1617import software .amazon .smithy .java .core .schema .SerializableStruct ;
1718import software .amazon .smithy .java .core .schema .TraitKey ;
1819import software .amazon .smithy .java .core .serde .Codec ;
2526import software .amazon .smithy .java .io .ByteBufferOutputStream ;
2627import software .amazon .smithy .java .io .datastream .DataStream ;
2728
29+ /**
30+ * Buffers the single {@code @httpPayload}-bound member into a {@link ByteBuffer}.
31+ *
32+ * <p>Because a payload binds exactly one member, this serializer receives exactly one top-level
33+ * write call.
34+ *
35+ * <ul>
36+ * <li>blob / data stream / event stream payloads hand the body off by reference via
37+ * {@link HttpBindingSerializer#setHttpPayload};</li>
38+ * <li>scalar payloads (string, number, boolean, timestamp) write their bytes directly into a
39+ * lazily-allocated {@link ByteBufferOutputStream};</li>
40+ * <li>structured payloads (struct, document, list, map) are serialized through the pooled
41+ * {@link Codec#serialize(SerializableShape)} path, which for JSON borrows a serializer from a
42+ * striped pool instead of allocating one.</li>
43+ * </ul>
44+ */
2845final class PayloadSerializer implements ShapeSerializer {
2946 private static final byte [] NULL_BYTES = "null" .getBytes (StandardCharsets .UTF_8 );
3047 private static final byte [] TRUE_BYTES = "true" .getBytes (StandardCharsets .UTF_8 );
3148 private static final byte [] FALSE_BYTES = "false" .getBytes (StandardCharsets .UTF_8 );
3249 private final HttpBindingSerializer serializer ;
33- private final ShapeSerializer structSerializer ;
34- private final ByteBufferOutputStream outputStream ;
50+ private final Codec codec ;
3551 private boolean payloadWritten = false ;
52+ private ByteBuffer codecResult ;
53+ private ByteBufferOutputStream scalarStream ;
3654
3755 PayloadSerializer (HttpBindingSerializer serializer , Codec codec ) {
3856 this .serializer = serializer ;
39- this .outputStream = new ByteBufferOutputStream ();
40- this .structSerializer = codec .createSerializer (outputStream );
57+ this .codec = codec ;
4158 }
4259
4360 @ Override
@@ -47,17 +64,21 @@ public void writeDataStream(Schema schema, DataStream value) {
4764 }
4865
4966 @ Override
50- public void writeEventStream (
51- Schema schema ,
52- EventStream <? extends SerializableStruct > value
53- ) {
67+ public void writeEventStream (Schema schema , EventStream <? extends SerializableStruct > value ) {
5468 payloadWritten = true ;
5569 serializer .setEventStream (value .asWriter ());
5670 }
5771
72+ private ByteBufferOutputStream scalarStream () {
73+ if (scalarStream == null ) {
74+ scalarStream = new ByteBufferOutputStream ();
75+ }
76+ return scalarStream ;
77+ }
78+
5879 private void write (byte [] bytes ) {
5980 try {
60- outputStream .write (bytes );
81+ scalarStream () .write (bytes );
6182 } catch (IOException e ) {
6283 throw new SerializationException (e );
6384 }
@@ -78,7 +99,7 @@ public void writeTimestamp(Schema schema, Instant value) {
7899 @ Override
79100 public void writeDocument (Schema schema , Document value ) {
80101 serializer .writePayloadContentType ();
81- structSerializer . writeDocument (schema , value );
102+ codecResult = codec . serialize ( ser -> ser . writeDocument (schema , value ) );
82103 }
83104
84105 @ Override
@@ -89,18 +110,18 @@ public void writeNull(Schema schema) {
89110 @ Override
90111 public void writeStruct (Schema schema , SerializableStruct struct ) {
91112 serializer .writePayloadContentType ();
92- structSerializer . writeStruct (schema , struct );
113+ codecResult = codec . serialize ( ser -> ser . writeStruct (schema , struct ) );
93114 }
94115
95116 @ Override
96117 public <T > void writeList (Schema schema , T listState , int size , BiConsumer <T , ShapeSerializer > consumer ) {
97118 serializer .writePayloadContentType ();
98- structSerializer . writeList (schema , listState , size , consumer );
119+ codecResult = codec . serialize ( ser -> ser . writeList (schema , listState , size , consumer ) );
99120 }
100121
101122 @ Override
102123 public <T > void writeMap (Schema schema , T mapState , int size , BiConsumer <T , MapSerializer > consumer ) {
103- structSerializer . writeMap (schema , mapState , size , consumer );
124+ codecResult = codec . serialize ( ser -> ser . writeMap (schema , mapState , size , consumer ) );
104125 }
105126
106127 @ Override
@@ -110,7 +131,7 @@ public void writeBoolean(Schema schema, boolean value) {
110131
111132 @ Override
112133 public void writeByte (Schema schema , byte value ) {
113- outputStream .write (value );
134+ scalarStream () .write (value );
114135 }
115136
116137 @ Override
@@ -165,31 +186,17 @@ public void writeBlob(Schema schema, ByteBuffer value) {
165186 serializer .setHttpPayload (schema , DataStream .ofByteBuffer (value ));
166187 }
167188
168- @ Override
169- public void flush () {
170- structSerializer .flush ();
171- try {
172- outputStream .flush ();
173- } catch (IOException e ) {
174- throw new SerializationException (e );
175- }
176- }
177-
178- @ Override
179- public void close () {
180- structSerializer .close ();
181- try {
182- outputStream .close ();
183- } catch (IOException e ) {
184- throw new SerializationException (e );
185- }
186- }
187-
188189 public boolean isPayloadWritten () {
189190 return payloadWritten ;
190191 }
191192
192193 ByteBuffer toByteBuffer () {
193- return outputStream .toByteBuffer ();
194+ if (codecResult != null ) {
195+ return codecResult ;
196+ } else if (scalarStream != null ) {
197+ return scalarStream .toByteBuffer ();
198+ } else {
199+ return ByteBuffer .allocate (0 );
200+ }
194201 }
195202}
0 commit comments