Skip to content

Commit

Permalink
Support auto construct lists
Browse files Browse the repository at this point in the history
  • Loading branch information
dagnir committed May 31, 2018
1 parent faeb049 commit a61c5fb
Show file tree
Hide file tree
Showing 52 changed files with 5,637 additions and 338 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ public class CustomizationConfig {

private Map<String, String> modelMarshallerDefaultValueSupplier;

private boolean useAutoConstructList = true;

private CustomizationConfig() {
}

Expand Down Expand Up @@ -336,4 +338,12 @@ public Map<String, String> getModelMarshallerDefaultValueSupplier() {
public void setModelMarshallerDefaultValueSupplier(Map<String, String> modelMarshallerDefaultValueSupplier) {
this.modelMarshallerDefaultValueSupplier = modelMarshallerDefaultValueSupplier;
}

public boolean isUseAutoConstructList() {
return useAutoConstructList;
}

public void setUseAutoConstructList(boolean useAutoConstructList) {
this.useAutoConstructList = useAutoConstructList;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package software.amazon.awssdk.codegen.poet.model;

import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
Expand Down Expand Up @@ -49,15 +50,16 @@ public MethodSpec beanStyleGetter(MemberModel memberModel) {
private MethodSpec regularGetter(MemberModel memberModel) {
return basicGetter(memberModel,
typeProvider.parameterType(memberModel),
"return $N",
memberModel.getVariable().getVariableName());
CodeBlock.builder().add("return $N", memberModel.getVariable().getVariableName())
.build());
}

private MethodSpec builderGetter(MemberModel memberModel) {
return basicGetter(memberModel,
poetExtensions.getModelClass(memberModel.getC2jShape()).nestedClass("Builder"),
"return $1N != null ? $1N.toBuilder() : null",
memberModel.getVariable().getVariableName());
CodeBlock.builder().add("return $1N != null ? $1N.toBuilder() : null",
memberModel.getVariable().getVariableName())
.build());
}

private MethodSpec mapOfBuildersGetter(MemberModel memberModel) {
Expand All @@ -68,10 +70,11 @@ private MethodSpec mapOfBuildersGetter(MemberModel memberModel) {

return basicGetter(memberModel,
returnType,
"return $1N != null ? $2T.mapValues($1N, $3T::toBuilder) : null",
memberModel.getVariable().getVariableName(),
CollectionUtils.class,
valueType);
CodeBlock.builder().add("return $1N != null ? $2T.mapValues($1N, $3T::toBuilder) : null",
memberModel.getVariable().getVariableName(),
CollectionUtils.class,
valueType)
.build());
}

private MethodSpec listOfBuildersGetter(MemberModel memberModel) {
Expand All @@ -80,17 +83,19 @@ private MethodSpec listOfBuildersGetter(MemberModel memberModel) {

return basicGetter(memberModel,
returnType,
"return $1N != null ? $1N.stream().map($2T::toBuilder).collect($3T.toList()) : null",
memberModel.getVariable().getVariableName(),
memberType,
Collectors.class);
CodeBlock.builder().add(
"return $1N != null ? $1N.stream().map($2T::toBuilder).collect($3T.toList()) : null",
memberModel.getVariable().getVariableName(),
memberType,
Collectors.class)
.build());
}

private MethodSpec basicGetter(MemberModel memberModel, TypeName returnType, String statementCode, Object...statementArgs) {
private MethodSpec basicGetter(MemberModel memberModel, TypeName returnType, CodeBlock statement) {
return MethodSpec.methodBuilder(memberModel.getBeanStyleGetterMethodName())
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.returns(returnType)
.addStatement(statementCode, statementArgs)
.addStatement(statement)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
import software.amazon.awssdk.codegen.poet.PoetUtils;
import software.amazon.awssdk.codegen.poet.StaticImport;
import software.amazon.awssdk.core.runtime.StandardMemberCopier;
import software.amazon.awssdk.core.util.DefaultSdkAutoConstructList;
import software.amazon.awssdk.core.util.SdkAutoConstructList;

class MemberCopierSpec implements ClassSpec {
private final MemberModel memberModel;
Expand Down Expand Up @@ -99,15 +101,15 @@ private MethodSpec.Builder copyMethodProto() {

private MethodSpec builderCopyMethod() {
if (memberModel.isList()) {
return builderCopyMethodForMap();
return builderCopyMethodForList();
}
if (memberModel.isMap()) {
return builderCopyMethodForList();
return builderCopyMethodForMap();
}
throw new UnsupportedOperationException();
}

private MethodSpec builderCopyMethodForList() {
private MethodSpec builderCopyMethodForMap() {
TypeName keyType = typeProvider.getTypeNameForSimpleType(memberModel.getMapModel().getKeyModel()
.getVariable().getVariableType());
ClassName valueParameter = poetExtensions.getModelClass(memberModel.getMapModel().getValueModel().getC2jShape());
Expand All @@ -134,7 +136,7 @@ private MethodSpec builderCopyMethodForList() {
.build();
}

private MethodSpec builderCopyMethodForMap() {
private MethodSpec builderCopyMethodForList() {
ClassName listParameter = poetExtensions.getModelClass(memberModel.getListModel().getListMemberModel().getC2jShape());
ClassName builderForParameter = listParameter.nestedClass("Builder");

Expand Down Expand Up @@ -176,18 +178,42 @@ private CodeBlock listCopyBody() {
String paramName = memberParamName();
MemberModel listMember = memberModel.getListModel().getListMemberModel();
String copyName = paramName + "Copy";
CodeBlock.Builder builder = CodeBlock.builder()
.beginControlFlow("if ($N == null)", memberParamName())
.addStatement("return null")
.endControlFlow()
.add("$T $N = $N.stream()", typeProvider.fieldType(memberModel), copyName, paramName);

serviceModelCopiers.copierClassFor(listMember)
.ifPresent(copyClass -> builder.add(".map($T::$N)", copyClass, serviceModelCopiers.copyMethodName()));
CodeBlock.Builder builder = CodeBlock.builder();

builder.add(".collect(toList());");
if (typeProvider.useAutoConstructLists()) {
builder.beginControlFlow("if ($1N == null || $1N instanceof $2T)", memberParamName(), SdkAutoConstructList.class)
.addStatement("return $T.getInstance()", DefaultSdkAutoConstructList.class)
.endControlFlow();

} else {
builder.beginControlFlow("if ($N == null)", memberParamName())
.addStatement("return null")
.endControlFlow();
}

return builder.addStatement("return $T.unmodifiableList($N)", Collections.class, copyName).build();
Optional<ClassName> elementCopier = serviceModelCopiers.copierClassFor(listMember);

// Just use constructor copy if there's no copier for the element
if (!elementCopier.isPresent()) {
builder.addStatement("$T $N = new $T<>($N)",
typeProvider.fieldType(memberModel),
copyName,
typeProvider.listImplClassName(),
paramName);
} else {
ClassName copier = elementCopier.get();
builder.addStatement("$T $N = $N.stream().map($T::$N).collect(toList())",
typeProvider.fieldType(memberModel),
copyName,
paramName,
copier,
serviceModelCopiers.copyMethodName());
}

builder.addStatement("return $T.unmodifiableList($N)", Collections.class, copyName);

return builder.build();
}

private CodeBlock mapCopyBody() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import javax.lang.model.element.Modifier;
import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration;
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
import software.amazon.awssdk.codegen.model.intermediate.ShapeModel;
import software.amazon.awssdk.codegen.model.intermediate.ShapeType;
import software.amazon.awssdk.codegen.poet.PoetExtensions;
import software.amazon.awssdk.core.util.DefaultSdkAutoConstructList;
import software.amazon.awssdk.utils.builder.CopyableBuilder;

/**
Expand Down Expand Up @@ -130,10 +132,20 @@ private TypeName builderImplSuperClass() {
}

private List<FieldSpec> fields() {
List<FieldSpec> fields = new ArrayList<>(shapeModelSpec.fields(Modifier.PRIVATE));
List<FieldSpec> fields = shapeModel.getNonStreamingMembers().stream()
.map(m -> {
FieldSpec fieldSpec = typeProvider.asField(m, Modifier.PRIVATE);
if (m.isList() && typeProvider.useAutoConstructLists()) {
fieldSpec = fieldSpec.toBuilder()
.initializer("$T.getInstance()", DefaultSdkAutoConstructList.class)
.build();
}
return fieldSpec;
}).collect(Collectors.toList());

// Inject a message member for the isException message
if (isException()) {
fields = new ArrayList<>(fields);
fields.add(FieldSpec.builder(String.class, "message", Modifier.PRIVATE).build());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import java.util.List;
import java.util.stream.Collectors;
import javax.lang.model.element.Modifier;
import software.amazon.awssdk.codegen.model.intermediate.MemberModel;
import software.amazon.awssdk.codegen.model.intermediate.ShapeModel;
import software.amazon.awssdk.codegen.poet.PoetExtensions;

Expand Down Expand Up @@ -48,19 +47,7 @@ public List<FieldSpec> fields() {

public List<FieldSpec> fields(Modifier... modifiers) {
return shapeModel.getNonStreamingMembers().stream()
.map(m -> asField(m, modifiers))
.map(m -> typeProvider.asField(m, modifiers))
.collect(Collectors.toList());
}

public FieldSpec asField(MemberModel memberModel, Modifier... modifiers) {
FieldSpec.Builder builder = FieldSpec.builder(typeProvider.fieldType(memberModel),
memberModel.getVariable().getVariableName());

if (modifiers != null) {
builder.addModifiers(modifiers);
}

return builder.build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package software.amazon.awssdk.codegen.poet.model;

import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.WildcardTypeName;
Expand All @@ -30,6 +31,7 @@
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import javax.lang.model.element.Modifier;
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
import software.amazon.awssdk.codegen.model.intermediate.ListModel;
import software.amazon.awssdk.codegen.model.intermediate.MapModel;
Expand All @@ -40,16 +42,22 @@
* Helper class for resolving Poet {@link TypeName}s for use in model classes.
*/
public class TypeProvider {
private final IntermediateModel intermediateModel;
private final PoetExtensions poetExtensions;

public TypeProvider(IntermediateModel intermediateModel) {
this.poetExtensions = new PoetExtensions(intermediateModel);
this.intermediateModel = intermediateModel;
this.poetExtensions = new PoetExtensions(this.intermediateModel);
}

public ClassName listImplClassName() {
return ClassName.get(ArrayList.class);
}

public boolean useAutoConstructLists() {
return intermediateModel.getCustomizationConfig().isUseAutoConstructList();
}

public ClassName mapImplClassName() {
return ClassName.get(HashMap.class);
}
Expand Down Expand Up @@ -160,4 +168,15 @@ public TypeName getTypeNameForSimpleType(String simpleType) {
.findFirst()
.orElseThrow(() -> new RuntimeException("Unsupported simple fieldType " + simpleType));
}

public FieldSpec asField(MemberModel memberModel, Modifier... modifiers) {
FieldSpec.Builder builder = FieldSpec.builder(fieldType(memberModel),
memberModel.getVariable().getVariableName());

if (modifiers != null) {
builder.addModifiers(modifiers);
}

return builder.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
@RunWith(Parameterized.class)
public class AwsModelSpecTest {
private static IntermediateModel intermediateModel;

private final ShapeModel shapeModel;

@Parameterized.Parameters(name = "{0}")
Expand All @@ -64,11 +65,13 @@ private static void setUp() throws IOException {
File customizationConfigFile = new File(AwsModelSpecTest.class
.getResource("customization.config")
.getFile());
ServiceModel serviceModel = ModelLoaderUtils.loadModel(ServiceModel.class, serviceModelFile);
CustomizationConfig basicConfig = ModelLoaderUtils.loadModel(CustomizationConfig.class, customizationConfigFile);

intermediateModel = new IntermediateModelBuilder(
C2jModels.builder()
.serviceModel(ModelLoaderUtils.loadModel(ServiceModel.class, serviceModelFile))
.customizationConfig(ModelLoaderUtils.loadModel(CustomizationConfig.class, customizationConfigFile))
.serviceModel(serviceModel)
.customizationConfig(basicConfig)
.build())
.build();
}
Expand Down
Loading

0 comments on commit a61c5fb

Please sign in to comment.