Skip to content

Commit 8f76ce3

Browse files
committed
Json Marshaller Refactor
1 parent d80e1ad commit 8f76ce3

File tree

30 files changed

+1516
-87
lines changed

30 files changed

+1516
-87
lines changed

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

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,19 @@
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.transform.JsonModelMarshallerSpec;
34+
import software.amazon.awssdk.codegen.poet.transform.MarshallerSpec;
3335
import software.amazon.awssdk.core.util.ImmutableMapParameter;
3436

3537
public class MarshallerGeneratorTasks extends BaseGeneratorTasks {
3638

3739
private final String transformClassDir;
38-
private final String requestTransformClassDir;
3940
private final Metadata metadata;
4041
private final Map<String, ShapeModel> shapes;
4142

4243
public MarshallerGeneratorTasks(GeneratorTaskParams dependencies) {
4344
super(dependencies);
4445
this.transformClassDir = dependencies.getPathProvider().getTransformDirectory();
45-
this.requestTransformClassDir = dependencies.getPathProvider().getRequestTransformDirectory();
4646
this.metadata = model.getMetadata();
4747
this.shapes = model.getShapes();
4848
}
@@ -51,9 +51,9 @@ public MarshallerGeneratorTasks(GeneratorTaskParams dependencies) {
5151
protected List<GeneratorTask> createTasks() throws Exception {
5252
info("Emitting marshaller classes");
5353
return model.getShapes().entrySet().stream()
54-
.filter(e -> shouldGenerate(e.getValue()))
55-
.flatMap(safeFunction(e -> createTask(e.getKey(), e.getValue())))
56-
.collect(Collectors.toList());
54+
.filter(e -> shouldGenerate(e.getValue()))
55+
.flatMap(safeFunction(e -> createTask(e.getKey(), e.getValue())))
56+
.collect(Collectors.toList());
5757
}
5858

5959
private boolean shouldGenerate(ShapeModel shapeModel) {
@@ -69,39 +69,33 @@ private boolean shouldGenerate(ShapeType shapeType) {
6969
}
7070

7171
private Stream<GeneratorTask> createTask(String javaShapeName, ShapeModel shapeModel) throws Exception {
72-
if (shapeModel.getShapeType() == ShapeType.Request && metadata.isJsonProtocol()) {
73-
return Stream.of(
74-
createMarshallerTask(javaShapeName,
75-
freemarker.getRequestMarshallerTemplate(),
76-
javaShapeName + "Marshaller",
77-
requestTransformClassDir),
78-
createMarshallerTask(javaShapeName,
79-
freemarker.getModelMarshallerTemplate(),
80-
javaShapeName + "ModelMarshaller",
81-
transformClassDir));
82-
} else {
83-
return Stream.of(
84-
createMarshallerTask(javaShapeName,
85-
freemarker.getModelMarshallerTemplate(),
86-
javaShapeName + "Marshaller",
87-
transformClassDir));
72+
if (metadata.isJsonProtocol()) {
73+
return ShapeType.Request == shapeModel.getShapeType() ?
74+
Stream.of(createPoetGeneratorTask(new JsonModelMarshallerSpec(model, shapeModel, "ModelMarshaller")),
75+
createPoetGeneratorTask(new MarshallerSpec(model, shapeModel))) :
76+
Stream.of(createPoetGeneratorTask(new JsonModelMarshallerSpec(model, shapeModel, "Marshaller")));
8877
}
78+
79+
return Stream.of(
80+
createMarshallerTask(javaShapeName,
81+
freemarker.getModelMarshallerTemplate(),
82+
javaShapeName + "Marshaller",
83+
transformClassDir));
8984
}
9085

9186
private GeneratorTask createMarshallerTask(String javaShapeName, Template template,
92-
String marshallerClassName, String marshallerDirectory)
93-
throws IOException {
87+
String marshallerClassName, String marshallerDirectory) throws IOException {
9488
Map<String, Object> marshallerDataModel = ImmutableMapParameter.<String, Object>builder()
95-
.put("fileHeader", model.getFileHeader())
96-
.put("shapeName", javaShapeName)
97-
.put("shapes", shapes)
98-
.put("metadata", metadata)
99-
.put("transformPackage", model.getMetadata().getFullTransformPackageName())
100-
.put("requestTransformPackage", model.getMetadata().getFullRequestTransformPackageName())
101-
.put("customConfig", model.getCustomizationConfig())
102-
.put("className", marshallerClassName)
103-
.put("protocolEnum", getProtocolEnumName())
104-
.build();
89+
.put("fileHeader", model.getFileHeader())
90+
.put("shapeName", javaShapeName)
91+
.put("shapes", shapes)
92+
.put("metadata", metadata)
93+
.put("transformPackage", model.getMetadata().getFullTransformPackageName())
94+
.put("requestTransformPackage", model.getMetadata().getFullRequestTransformPackageName())
95+
.put("customConfig", model.getCustomizationConfig())
96+
.put("className", marshallerClassName)
97+
.put("protocolEnum", getProtocolEnumName())
98+
.build();
10599

106100
return new FreemarkerGeneratorTask(marshallerDirectory,
107101
marshallerClassName,

codegen/src/main/java/software/amazon/awssdk/codegen/internal/Freemarker.java

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -99,22 +99,10 @@ private Template getTemplate(TopLevelTemplate template) throws IOException {
9999
return fmConfig.getTemplate(template.getMainTemplate());
100100
}
101101

102-
public Template getSyncClientBuilderTemplate() throws IOException {
103-
return getTemplate(templateConfig.getSyncClientBuilder());
104-
}
105-
106-
public Template getAsyncClientBuilderTemplate() throws IOException {
107-
return getTemplate(templateConfig.getAsyncClientBuilder());
108-
}
109-
110102
public Template getModelMarshallerTemplate() throws IOException {
111103
return getTemplate(templateConfig.getModelMarshaller());
112104
}
113105

114-
public Template getRequestMarshallerTemplate() throws IOException {
115-
return getTemplate(templateConfig.getRequestMarshaller());
116-
}
117-
118106
public Template getModelUnmarshallerTemplate() throws IOException {
119107
return getTemplate(templateConfig.getModelUnmarshaller());
120108
}

codegen/src/main/java/software/amazon/awssdk/codegen/model/config/customization/CustomizationConfig.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ public class CustomizationConfig {
121121
private String sdkResponseBaseClassName;
122122
private String defaultExceptionUnmarshaller;
123123

124+
private Map<String, String> modelMarshallerDefaultValueSupplier;
125+
124126
private CustomizationConfig() {
125127
}
126128

@@ -312,4 +314,12 @@ public String getDefaultExceptionUnmarshaller() {
312314
public void setDefaultExceptionUnmarshaller(String defaultExceptionUnmarshaller) {
313315
this.defaultExceptionUnmarshaller = defaultExceptionUnmarshaller;
314316
}
317+
318+
public Map<String, String> getModelMarshallerDefaultValueSupplier() {
319+
return modelMarshallerDefaultValueSupplier;
320+
}
321+
322+
public void setModelMarshallerDefaultValueSupplier(Map<String, String> modelMarshallerDefaultValueSupplier) {
323+
this.modelMarshallerDefaultValueSupplier = modelMarshallerDefaultValueSupplier;
324+
}
315325
}
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
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;
17+
18+
import com.squareup.javapoet.ClassName;
19+
import com.squareup.javapoet.CodeBlock;
20+
import com.squareup.javapoet.FieldSpec;
21+
import com.squareup.javapoet.MethodSpec;
22+
import com.squareup.javapoet.ParameterizedTypeName;
23+
import com.squareup.javapoet.TypeName;
24+
import com.squareup.javapoet.TypeSpec;
25+
import java.util.ArrayList;
26+
import java.util.List;
27+
import java.util.Map;
28+
import java.util.Optional;
29+
import javax.lang.model.element.Modifier;
30+
import software.amazon.awssdk.annotations.SdkInternalApi;
31+
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
32+
import software.amazon.awssdk.codegen.model.intermediate.MemberModel;
33+
import software.amazon.awssdk.codegen.model.intermediate.ShapeModel;
34+
import software.amazon.awssdk.codegen.poet.ClassSpec;
35+
import software.amazon.awssdk.codegen.poet.PoetExtensions;
36+
import software.amazon.awssdk.codegen.poet.PoetUtils;
37+
import software.amazon.awssdk.core.exception.SdkClientException;
38+
import software.amazon.awssdk.core.protocol.MarshallLocation;
39+
import software.amazon.awssdk.core.protocol.MarshallingInfo;
40+
import software.amazon.awssdk.core.protocol.MarshallingType;
41+
import software.amazon.awssdk.core.protocol.ProtocolMarshaller;
42+
import software.amazon.awssdk.core.protocol.StructuredPojo;
43+
import software.amazon.awssdk.core.util.IdempotentUtils;
44+
import software.amazon.awssdk.utils.Validate;
45+
46+
/**
47+
* Create ModelMarshaller for Json protocol
48+
*/
49+
public class JsonModelMarshallerSpec implements ClassSpec {
50+
51+
private final IntermediateModel intermediateModel;
52+
private final ShapeModel shapeModel;
53+
private final ClassName className;
54+
private final ClassName requestClassName;
55+
56+
public JsonModelMarshallerSpec(IntermediateModel intermediateModel, ShapeModel shapeModel, String className) {
57+
PoetExtensions poetExtensions = new PoetExtensions(intermediateModel);
58+
String modelPackage = intermediateModel.getMetadata().getFullModelPackageName();
59+
this.intermediateModel = intermediateModel;
60+
this.shapeModel = shapeModel;
61+
this.className = poetExtensions.getTransformClass(shapeModel.getShapeName() + className);
62+
this.requestClassName = ClassName.get(modelPackage, shapeModel.getShapeName());
63+
}
64+
65+
@Override
66+
public TypeSpec poetSpec() {
67+
return TypeSpec.classBuilder(className)
68+
.addModifiers(Modifier.PUBLIC)
69+
.addAnnotation(PoetUtils.GENERATED)
70+
.addAnnotation(SdkInternalApi.class)
71+
.addJavadoc("{@link $T} Marshaller", requestClassName)
72+
.addFields(memberVariables())
73+
.addMethods(methods())
74+
.build();
75+
}
76+
77+
@Override
78+
public ClassName className() {
79+
return className;
80+
}
81+
82+
private List<MethodSpec> methods() {
83+
List<MethodSpec> methodSpecs = new ArrayList<>();
84+
85+
methodSpecs.add(constructor());
86+
methodSpecs.add(getInstanceMethod());
87+
methodSpecs.add(marshallMethod());
88+
return methodSpecs;
89+
}
90+
91+
private List<FieldSpec> memberVariables() {
92+
List<FieldSpec> fields = new ArrayList<>();
93+
94+
FieldSpec instance = FieldSpec.builder(className, "INSTANCE")
95+
.addModifiers(Modifier.PRIVATE, Modifier.FINAL, Modifier.STATIC)
96+
.initializer("new $T()", className)
97+
.build();
98+
99+
for (MemberModel memberModel : shapeModel.getNonStreamingMembers()) {
100+
TypeName typeName = ParameterizedTypeName.get(ClassName.get(MarshallingInfo.class),
101+
marshallingTargetClass(memberModel.getMarshallingTargetClass(),
102+
memberModel.getVariable().getVariableType()));
103+
104+
CodeBlock.Builder initializationCodeBlockBuilder = CodeBlock.builder()
105+
.add("$T.builder($T.$L).marshallLocation($T.$L)",
106+
MarshallingInfo.class,
107+
MarshallingType.class,
108+
memberModel.getMarshallingType(),
109+
ClassName.get(MarshallLocation.class),
110+
memberModel.getHttp().getMarshallLocation());
111+
112+
if (memberModel.getHttp().getIsPayload()) {
113+
initializationCodeBlockBuilder.add(".isExplicitPayloadMember($L)", memberModel.getHttp().getIsPayload());
114+
} else {
115+
initializationCodeBlockBuilder.add(".marshallLocationName($S)", memberModel.getHttp().getMarshallLocationName());
116+
}
117+
118+
initializationCodeBlockBuilder.add(".isBinary($L)", memberModel.getIsBinary());
119+
120+
Optional.ofNullable(intermediateModel.getCustomizationConfig().getModelMarshallerDefaultValueSupplier())
121+
.map(defaultValueSupplier -> defaultValueSupplier.get(memberModel.getName()))
122+
.ifPresent(value -> initializationCodeBlockBuilder.add(".defaultValueSupplier($L)", value));
123+
124+
if (memberModel.isIdempotencyToken()) {
125+
initializationCodeBlockBuilder.add(".defaultValueSupplier($T.getGenerator())", ClassName.get(IdempotentUtils
126+
.class));
127+
}
128+
129+
CodeBlock codeBlock = initializationCodeBlockBuilder.add(".build()").build();
130+
131+
FieldSpec fieldSpec = FieldSpec.builder(typeName, memberModel.getMarshallerBindingFieldName())
132+
.addModifiers(Modifier.PRIVATE, Modifier.FINAL, Modifier.STATIC)
133+
.initializer(codeBlock)
134+
.build();
135+
fields.add(fieldSpec);
136+
}
137+
138+
fields.add(instance);
139+
return fields;
140+
}
141+
142+
private MethodSpec constructor() {
143+
return MethodSpec.constructorBuilder().addModifiers(Modifier.PRIVATE).build();
144+
}
145+
146+
private MethodSpec getInstanceMethod() {
147+
return MethodSpec.methodBuilder("getInstance").addModifiers(Modifier.STATIC, Modifier.PUBLIC)
148+
.addStatement("return INSTANCE")
149+
.returns(className)
150+
.build();
151+
}
152+
153+
private MethodSpec marshallMethod() {
154+
String variableName = shapeModel.getVariable().getVariableName();
155+
MethodSpec.Builder methodSpecBuilder = MethodSpec.methodBuilder("marshall")
156+
.addJavadoc("Marshall the given parameter object")
157+
.addModifiers(Modifier.PUBLIC)
158+
.addParameter(requestClassName, variableName)
159+
.addParameter(ProtocolMarshaller.class, "protocolMarshaller");
160+
161+
if (shapeModel.getNonStreamingMembers().isEmpty()) {
162+
return methodSpecBuilder.build();
163+
}
164+
165+
methodSpecBuilder.addStatement("$T.paramNotNull($L, $S)", ClassName.get(Validate.class), variableName, variableName);
166+
methodSpecBuilder.addStatement("$T.paramNotNull($L, $S)", ClassName.get(Validate.class), "protocolMarshaller",
167+
"protocolMarshaller");
168+
169+
methodSpecBuilder.beginControlFlow("try");
170+
shapeModel.getNonStreamingMembers().forEach(
171+
memberModel -> methodSpecBuilder.addStatement("protocolMarshaller.marshall($L.$L(), $L)",
172+
variableName,
173+
memberModel.getFluentGetterMethodName(),
174+
memberModel.getMarshallerBindingFieldName()));
175+
176+
methodSpecBuilder.endControlFlow();
177+
methodSpecBuilder.beginControlFlow("catch (Exception e)");
178+
methodSpecBuilder.addStatement("throw new $T(\"Unable to marshall request to JSON: \" + e.getMessage(), e)", ClassName
179+
.get(SdkClientException.class));
180+
methodSpecBuilder.endControlFlow();
181+
return methodSpecBuilder.build();
182+
}
183+
184+
private ClassName marshallingTargetClass(String marshallerTargetClass, String variableType) {
185+
if ("List".equals(marshallerTargetClass)) {
186+
return ClassName.get(List.class);
187+
} else if ("String".equals(marshallerTargetClass)) {
188+
return ClassName.get(String.class);
189+
} else if ("Map".equals(marshallerTargetClass)) {
190+
return ClassName.get(Map.class);
191+
} else if ("StructuredPojo".equals(marshallerTargetClass)) {
192+
return ClassName.get(StructuredPojo.class);
193+
} else {
194+
return ClassName.bestGuess(variableType);
195+
}
196+
}
197+
}

0 commit comments

Comments
 (0)