Skip to content

Commit 28a5f48

Browse files
committed
Generate marshallers for h2 request events
1 parent 716acc5 commit 28a5f48

File tree

9 files changed

+156
-26
lines changed

9 files changed

+156
-26
lines changed

codegen/src/main/java/software/amazon/awssdk/codegen/emitters/tasks/MarshallerGeneratorTasks.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import software.amazon.awssdk.codegen.model.intermediate.Metadata;
3131
import software.amazon.awssdk.codegen.model.intermediate.ShapeModel;
3232
import software.amazon.awssdk.codegen.model.intermediate.ShapeType;
33+
import software.amazon.awssdk.codegen.poet.eventstream.EventStreamUtils;
3334
import software.amazon.awssdk.codegen.poet.transform.MarshallerSpec;
3435
import software.amazon.awssdk.utils.ImmutableMap;
3536

@@ -68,9 +69,12 @@ private boolean shouldGenerate(ShapeModel shapeModel) {
6869

6970
private Stream<GeneratorTask> createTask(String javaShapeName, ShapeModel shapeModel) throws Exception {
7071
if (metadata.isJsonProtocol()) {
71-
return ShapeType.Request == shapeModel.getShapeType() ?
72-
Stream.of(createPoetGeneratorTask(new MarshallerSpec(model, shapeModel))) :
73-
Stream.empty();
72+
73+
return ShapeType.Request == shapeModel.getShapeType() ||
74+
(ShapeType.Model == shapeModel.getShapeType() && shapeModel.isEvent()
75+
&& EventStreamUtils.isRequestEvent(model, shapeModel))
76+
? Stream.of(createPoetGeneratorTask(new MarshallerSpec(model, shapeModel)))
77+
: Stream.empty();
7478
}
7579

7680
return Stream.of(

codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/ShapeModelSpec.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ private CodeBlock traits(MemberModel m) {
150150
} else if (m.isMap()) {
151151
traits.add(createMapTrait(m));
152152
}
153-
if (m.getHttp().getIsPayload()) {
153+
if (m.getHttp().getIsPayload() || m.isEventPayload()) {
154154
traits.add(createPayloadTrait());
155155
}
156156
if (m.isJsonValue()) {

codegen/src/main/java/software/amazon/awssdk/codegen/poet/transform/MarshallerSpec.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import software.amazon.awssdk.codegen.poet.ClassSpec;
3030
import software.amazon.awssdk.codegen.poet.PoetExtensions;
3131
import software.amazon.awssdk.codegen.poet.PoetUtils;
32+
import software.amazon.awssdk.codegen.poet.transform.protocols.EventStreamJsonMarshallerSpec;
3233
import software.amazon.awssdk.codegen.poet.transform.protocols.JsonMarshallerSpec;
3334
import software.amazon.awssdk.codegen.poet.transform.protocols.MarshallerProtocolSpec;
3435
import software.amazon.awssdk.core.Request;
@@ -119,7 +120,7 @@ private MarshallerProtocolSpec getProtocolSpecs(software.amazon.awssdk.codegen.m
119120
case CBOR:
120121
case ION:
121122
case AWS_JSON:
122-
return new JsonMarshallerSpec(intermediateModel, shapeModel);
123+
return getJsonMarshallerSpec();
123124
case QUERY:
124125
case REST_XML:
125126
case EC2:
@@ -129,4 +130,11 @@ private MarshallerProtocolSpec getProtocolSpecs(software.amazon.awssdk.codegen.m
129130
throw new RuntimeException("Unknown protocol: " + protocol.name());
130131
}
131132
}
133+
134+
private MarshallerProtocolSpec getJsonMarshallerSpec() {
135+
if (shapeModel.isEvent()) {
136+
return new EventStreamJsonMarshallerSpec(intermediateModel, shapeModel);
137+
}
138+
return new JsonMarshallerSpec(intermediateModel, shapeModel);
139+
}
132140
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* Copyright 2010-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.codegen.poet.transform.protocols;
17+
18+
import com.squareup.javapoet.ClassName;
19+
import com.squareup.javapoet.CodeBlock;
20+
import com.squareup.javapoet.FieldSpec;
21+
import javax.lang.model.element.Modifier;
22+
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
23+
import software.amazon.awssdk.codegen.model.intermediate.MemberModel;
24+
import software.amazon.awssdk.codegen.model.intermediate.ShapeModel;
25+
import software.amazon.awssdk.codegen.poet.eventstream.EventStreamUtils;
26+
import software.amazon.awssdk.core.Request;
27+
import software.amazon.awssdk.core.protocol.OperationInfo;
28+
import software.amazon.awssdk.core.protocol.ProtocolMarshaller;
29+
30+
/**
31+
* MarshallerSpec for event shapes in Json protocol
32+
*/
33+
public final class EventStreamJsonMarshallerSpec extends JsonMarshallerSpec {
34+
35+
private static final String JSON_CONTENT_TYPE = "application/json";
36+
37+
private final IntermediateModel intermediateModel;
38+
39+
public EventStreamJsonMarshallerSpec(IntermediateModel model, ShapeModel shapeModel) {
40+
super(model, shapeModel);
41+
this.intermediateModel = model;
42+
}
43+
44+
@Override
45+
public CodeBlock marshalCodeBlock(ClassName requestClassName) {
46+
String variableName = shapeModel.getVariable().getVariableName();
47+
CodeBlock.Builder builder =
48+
CodeBlock.builder()
49+
.addStatement("$T<$T<$T>> protocolMarshaller = protocolFactory.createProtocolMarshaller"
50+
+ "(SDK_OPERATION_BINDING, $L)",
51+
ProtocolMarshaller.class, Request.class,
52+
requestClassName, variableName)
53+
.addStatement("$T<$T> request = protocolMarshaller.marshall($L)",
54+
Request.class, requestClassName, variableName)
55+
.addStatement("request.addHeader(\":message-type\", \"event\")")
56+
.addStatement("request.addHeader(\":event-type\", \"$L\")", getMemberNameFromEventStream());
57+
58+
// Add :content-type header only if payload is present
59+
if (!shapeModel.hasNoEventPayload()) {
60+
builder.addStatement("request.addHeader(\":content-type\", \"$L\")", determinePayloadContentType());
61+
}
62+
63+
builder.addStatement("return request");
64+
65+
return builder.build();
66+
}
67+
68+
@Override
69+
protected FieldSpec operationInfoField() {
70+
CodeBlock.Builder builder =
71+
CodeBlock.builder()
72+
.add("$T.builder()", OperationInfo.class)
73+
.add(".hasExplicitPayloadMember($L)", shapeModel.isHasPayloadMember() ||
74+
shapeModel.getExplicitEventPayloadMember() != null)
75+
.add(".hasPayloadMembers($L)", shapeModel.hasPayloadMembers())
76+
.add(".build()");
77+
78+
79+
return FieldSpec.builder(ClassName.get(OperationInfo.class), "SDK_OPERATION_BINDING")
80+
.addModifiers(Modifier.PRIVATE, Modifier.FINAL, Modifier.STATIC)
81+
.initializer(builder.build())
82+
.build();
83+
}
84+
85+
private String getMemberNameFromEventStream() {
86+
ShapeModel eventStream = EventStreamUtils.getBaseEventStreamShape(intermediateModel, shapeModel);
87+
return eventStream.getMembers().stream()
88+
.filter(memberModel -> memberModel.getShape().equals(shapeModel))
89+
.findAny()
90+
.map(MemberModel::getC2jName)
91+
.orElseThrow(() -> new IllegalStateException(
92+
String.format("Unable to find %s from its parent event stream", shapeModel.getC2jName())));
93+
}
94+
95+
private String determinePayloadContentType() {
96+
MemberModel explicitEventPayload = shapeModel.getExplicitEventPayloadMember();
97+
if (explicitEventPayload != null) {
98+
return getPayloadContentType(explicitEventPayload);
99+
}
100+
101+
return JSON_CONTENT_TYPE;
102+
}
103+
104+
private String getPayloadContentType(MemberModel memberModel) {
105+
final String blobContentType = "application/octet-stream";
106+
final String stringContentType = "text/plain";
107+
final String variableType = memberModel.getVariable().getVariableType();
108+
109+
if ("software.amazon.awssdk.core.SdkBytes".equals(variableType)) {
110+
return blobContentType;
111+
} else if ("String".equals(variableType)) {
112+
return stringContentType;
113+
}
114+
115+
return JSON_CONTENT_TYPE;
116+
}
117+
}

codegen/src/main/java/software/amazon/awssdk/codegen/poet/transform/protocols/JsonMarshallerSpec.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@
3939
*/
4040
public class JsonMarshallerSpec implements MarshallerProtocolSpec {
4141

42-
private final Metadata metadata;
43-
private final ShapeModel shapeModel;
42+
protected final Metadata metadata;
43+
protected final ShapeModel shapeModel;
4444

4545
public JsonMarshallerSpec(IntermediateModel model, ShapeModel shapeModel) {
4646
this.metadata = model.getMetadata();
@@ -82,7 +82,12 @@ public FieldSpec protocolFactory() {
8282
@Override
8383
public List<FieldSpec> memberVariables() {
8484
List<FieldSpec> fields = new ArrayList<>();
85+
fields.add(operationInfoField());
86+
fields.add(protocolFactory());
87+
return fields;
88+
}
8589

90+
protected FieldSpec operationInfoField() {
8691
CodeBlock.Builder initializationCodeBlockBuilder = CodeBlock.builder()
8792
.add("$T.builder()", OperationInfo.class);
8893
initializationCodeBlockBuilder.add(".requestUri($S)", shapeModel.getMarshaller().getRequestUri())
@@ -102,12 +107,9 @@ public List<FieldSpec> memberVariables() {
102107

103108
CodeBlock codeBlock = initializationCodeBlockBuilder.add(".build()").build();
104109

105-
FieldSpec.Builder instance = FieldSpec.builder(ClassName.get(OperationInfo.class), "SDK_OPERATION_BINDING")
106-
.addModifiers(Modifier.PRIVATE, Modifier.FINAL, Modifier.STATIC)
107-
.initializer(codeBlock);
108-
109-
fields.add(instance.build());
110-
fields.add(protocolFactory());
111-
return fields;
110+
return FieldSpec.builder(ClassName.get(OperationInfo.class), "SDK_OPERATION_BINDING")
111+
.addModifiers(Modifier.PRIVATE, Modifier.FINAL, Modifier.STATIC)
112+
.initializer(codeBlock)
113+
.build();
112114
}
113115
}

codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/inputevent.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import software.amazon.awssdk.core.protocol.SdkField;
1717
import software.amazon.awssdk.core.protocol.SdkPojo;
1818
import software.amazon.awssdk.core.protocol.traits.LocationTrait;
19+
import software.amazon.awssdk.core.protocol.traits.PayloadTrait;
1920
import software.amazon.awssdk.utils.ToString;
2021
import software.amazon.awssdk.utils.builder.CopyableBuilder;
2122
import software.amazon.awssdk.utils.builder.ToCopyableBuilder;
@@ -25,10 +26,11 @@
2526
@Generated("software.amazon.awssdk:codegen")
2627
public final class InputEvent implements SdkPojo, ToCopyableBuilder<InputEvent.Builder, InputEvent>, InputEventStream {
2728
private static final SdkField<SdkBytes> EXPLICIT_PAYLOAD_MEMBER_FIELD = SdkField
28-
.<SdkBytes> builder(MarshallingType.SDK_BYTES).getter(getter(InputEvent::explicitPayloadMember))
29-
.setter(setter(Builder::explicitPayloadMember))
30-
.traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ExplicitPayloadMember").build())
31-
.build();
29+
.<SdkBytes> builder(MarshallingType.SDK_BYTES)
30+
.getter(getter(InputEvent::explicitPayloadMember))
31+
.setter(setter(Builder::explicitPayloadMember))
32+
.traits(LocationTrait.builder().location(MarshallLocation.PAYLOAD).locationName("ExplicitPayloadMember").build(),
33+
PayloadTrait.create()).build();
3234

3335
private static final List<SdkField<?>> SDK_FIELDS = Collections
3436
.unmodifiableList(Arrays.asList(EXPLICIT_PAYLOAD_MEMBER_FIELD));
@@ -156,4 +158,3 @@ public List<SdkField<?>> sdkFields() {
156158
}
157159
}
158160
}
159-

core/aws-core/src/main/java/software/amazon/awssdk/awscore/protocol/json/AwsJsonProtocolFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ private AwsStructuredJsonFactory getSdkFactory() {
171171
}
172172
}
173173

174-
public <T extends software.amazon.awssdk.awscore.AwsRequest> ProtocolMarshaller<Request<T>> createProtocolMarshaller(
174+
public <T> ProtocolMarshaller<Request<T>> createProtocolMarshaller(
175175
OperationInfo operationInfo, T origRequest) {
176176
return JsonProtocolMarshallerBuilder.<T>standard()
177177
.jsonGenerator(createGenerator(operationInfo))

core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/protocol/json/JsonProtocolMarshaller.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import software.amazon.awssdk.core.DefaultRequest;
2424
import software.amazon.awssdk.core.Request;
2525
import software.amazon.awssdk.core.SdkBytes;
26-
import software.amazon.awssdk.core.SdkRequest;
2726
import software.amazon.awssdk.core.protocol.MarshallingType;
2827
import software.amazon.awssdk.core.protocol.OperationInfo;
2928
import software.amazon.awssdk.core.protocol.ProtocolRequestMarshaller;
@@ -40,7 +39,7 @@
4039
* @param <OrigRequestT> Type of the original request object.
4140
*/
4241
@SdkInternalApi
43-
public class JsonProtocolMarshaller<OrigRequestT extends SdkRequest> implements ProtocolRequestMarshaller<OrigRequestT> {
42+
public class JsonProtocolMarshaller<OrigRequestT> implements ProtocolRequestMarshaller<OrigRequestT> {
4443

4544
private static final MarshallerRegistry MARSHALLER_REGISTRY = createMarshallerRegistry();
4645

core/sdk-core/src/main/java/software/amazon/awssdk/core/protocol/json/JsonProtocolMarshallerBuilder.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
package software.amazon.awssdk.core.protocol.json;
1717

1818
import software.amazon.awssdk.annotations.SdkProtectedApi;
19-
import software.amazon.awssdk.core.SdkRequest;
2019
import software.amazon.awssdk.core.internal.protocol.json.JsonProtocolMarshaller;
2120
import software.amazon.awssdk.core.internal.protocol.json.NullAsEmptyBodyProtocolRequestMarshaller;
2221
import software.amazon.awssdk.core.protocol.OperationInfo;
@@ -28,16 +27,16 @@
2827
* @param <T> Type of the original request object.
2928
*/
3029
@SdkProtectedApi
31-
public class JsonProtocolMarshallerBuilder<T extends SdkRequest> {
30+
public class JsonProtocolMarshallerBuilder<T> {
3231

3332
private StructuredJsonGenerator jsonGenerator;
3433
private String contentType;
3534
private OperationInfo operationInfo;
3635
private boolean sendExplicitNullForPayload;
3736
private T originalRequest;
3837

39-
public static <T extends SdkRequest> JsonProtocolMarshallerBuilder<T> standard() {
40-
return new JsonProtocolMarshallerBuilder<T>();
38+
public static <T> JsonProtocolMarshallerBuilder<T> standard() {
39+
return new JsonProtocolMarshallerBuilder<>();
4140
}
4241

4342
public JsonProtocolMarshallerBuilder<T> jsonGenerator(StructuredJsonGenerator jsonGenerator) {

0 commit comments

Comments
 (0)