Skip to content

Commit 710b3af

Browse files
committed
Implementing Consumer<Builder> fluent setters on model builders.
1 parent 9c50013 commit 710b3af

File tree

8 files changed

+316
-55
lines changed

8 files changed

+316
-55
lines changed

codegen/src/main/java/software/amazon/awssdk/codegen/model/intermediate/MemberModel.java

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -377,33 +377,56 @@ private boolean returnTypeIs(Class<?> clazz) {
377377
}
378378

379379
public String getFluentSetterDocumentation() {
380-
StringBuilder docBuilder = new StringBuilder();
381-
docBuilder.append(getSetterDocumentation())
382-
.append(LF)
383-
.append("@return " + stripHtmlTags(DEFAULT_FLUENT_RETURN))
384-
.append(getEnumDoc());
385-
return docBuilder.toString();
380+
return getSetterDocumentation()
381+
+ LF
382+
+ "@return " + stripHtmlTags(DEFAULT_FLUENT_RETURN)
383+
+ getEnumDoc();
384+
}
385+
386+
public String getDefaultConsumerFluentSetterDocumentation() {
387+
return (StringUtils.isNotBlank(documentation) ? documentation : DEFAULT_SETTER.replace("%s", name) + "\n")
388+
+ LF
389+
+ "This is a convenience that creates an instance of the {@link "
390+
+ variable.getSimpleType()
391+
+ ".Builder} avoiding the need to create one manually via {@link "
392+
+ variable.getSimpleType()
393+
+ "#builder()}.\n"
394+
+ LF
395+
+ "When the {@link Consumer} completes, {@link "
396+
+ variable.getSimpleType()
397+
+ ".Builder#build()} is called immediately and its result is passed to {@link #"
398+
+ getFluentGetterMethodName()
399+
+ "("
400+
+ variable.getSimpleType()
401+
+ ")}."
402+
+ LF
403+
+ "@param "
404+
+ variable.getVariableName()
405+
+ " a consumer that will call methods on {@link "
406+
+ variable.getSimpleType() + ".Builder}"
407+
+ LF
408+
+ "@return " + stripHtmlTags(DEFAULT_FLUENT_RETURN)
409+
+ LF
410+
+ "@see #"
411+
+ getFluentSetterMethodName()
412+
+ "("
413+
+ variable.getSimpleType()
414+
+ ")";
386415
}
387416

388417
private String getParamDoc() {
389-
StringBuilder docBuilder = new StringBuilder();
390-
391-
String variableDesc = StringUtils.isNotBlank(documentation) ? documentation : DEFAULT_SETTER_PARAM.replace("%s", name);
392-
393-
docBuilder.append(LF)
394-
.append("@param ")
395-
.append(variable.getVariableName())
396-
.append(" ")
397-
.append(stripHtmlTags(variableDesc));
398-
return docBuilder.toString();
418+
return LF
419+
+ "@param "
420+
+ variable.getVariableName()
421+
+ " "
422+
+ stripHtmlTags(StringUtils.isNotBlank(documentation) ? documentation : DEFAULT_SETTER_PARAM.replace("%s", name));
399423
}
400424

401425
private String getEnumDoc() {
402426
StringBuilder docBuilder = new StringBuilder();
403427

404428
if (enumType != null) {
405-
docBuilder.append(LF);
406-
docBuilder.append("@see " + enumType);
429+
docBuilder.append(LF).append("@see ").append(enumType);
407430
}
408431

409432
return docBuilder.toString();

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

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,12 @@ abstract class AbstractMemberSetters implements MemberSetters {
5454
this.poetExtensions = new PoetExtensions(intermediateModel);
5555
}
5656

57-
protected MethodSpec.Builder fluentSetterDeclaration(ParameterSpec parameter, TypeName returnType) {
58-
return MethodSpec.methodBuilder(memberModel().getFluentSetterMethodName())
59-
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
60-
.addParameter(parameter)
61-
.returns(returnType);
57+
protected MethodSpec.Builder fluentAbstractSetterDeclaration(ParameterSpec parameter, TypeName returnType) {
58+
return fluentSetterDeclaration(parameter, returnType).addModifiers(Modifier.ABSTRACT);
59+
}
60+
61+
protected MethodSpec.Builder fluentDefaultSetterDeclaration(ParameterSpec parameter, TypeName returnType) {
62+
return fluentSetterDeclaration(parameter, returnType).addModifiers(Modifier.DEFAULT);
6263
}
6364

6465
protected MethodSpec.Builder fluentSetterBuilder(TypeName returnType) {
@@ -142,6 +143,13 @@ protected boolean annotateJsonProperty() {
142143
return intermediateModel.getMetadata().isJsonProtocol() && shapeModel.getShapeType() == ShapeType.Exception;
143144
}
144145

146+
private MethodSpec.Builder fluentSetterDeclaration(ParameterSpec parameter, TypeName returnType) {
147+
return MethodSpec.methodBuilder(memberModel().getFluentSetterMethodName())
148+
.addModifiers(Modifier.PUBLIC)
149+
.addParameter(parameter)
150+
.returns(returnType);
151+
}
152+
145153
private CodeBlock copySetterBody(String copyAssignment, String regularAssignment, String copyMethodName) {
146154
Optional<ClassName> copierClass = serviceModelCopiers.copierClassFor(memberModel);
147155

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,17 +49,17 @@ public List<MethodSpec> fluentDeclarations(TypeName returnType) {
4949

5050
String setterDocumentation = memberModel().getFluentSetterDocumentation();
5151

52-
fluentDeclarations.add(fluentSetterDeclaration(memberAsParameter(), returnType)
52+
fluentDeclarations.add(fluentAbstractSetterDeclaration(memberAsParameter(), returnType)
5353
.addJavadoc("$L", setterDocumentation)
5454
.build());
5555

56-
fluentDeclarations.add(fluentSetterDeclaration(ParameterSpec.builder(asArray(), fieldName()).build(), returnType)
56+
fluentDeclarations.add(fluentAbstractSetterDeclaration(ParameterSpec.builder(asArray(), fieldName()).build(), returnType)
5757
.addJavadoc("$L", setterDocumentation)
5858
.varargs(true)
5959
.build());
6060

6161
if (memberModel().getEnumType() != null) {
62-
fluentDeclarations.add(fluentSetterDeclaration(ParameterSpec.builder(
62+
fluentDeclarations.add(fluentAbstractSetterDeclaration(ParameterSpec.builder(
6363
asArrayOfModeledEnum(), fieldName()).build(), returnType)
6464
.varargs(true)
6565
.addJavadoc("$L", setterDocumentation)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class MapSetters extends AbstractMemberSetters {
3232
}
3333

3434
public List<MethodSpec> fluentDeclarations(TypeName returnType) {
35-
return Collections.singletonList(fluentSetterDeclaration(memberAsParameter(), returnType)
35+
return Collections.singletonList(fluentAbstractSetterDeclaration(memberAsParameter(), returnType)
3636
.addJavadoc("$L", memberModel().getFluentSetterDocumentation())
3737
.build());
3838
}

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

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,16 @@
1717

1818
import com.fasterxml.jackson.annotation.JsonProperty;
1919
import com.squareup.javapoet.AnnotationSpec;
20+
import com.squareup.javapoet.ClassName;
2021
import com.squareup.javapoet.CodeBlock;
2122
import com.squareup.javapoet.MethodSpec;
2223
import com.squareup.javapoet.ParameterSpec;
24+
import com.squareup.javapoet.ParameterizedTypeName;
2325
import com.squareup.javapoet.TypeName;
2426
import java.util.ArrayList;
2527
import java.util.List;
28+
import java.util.function.Consumer;
29+
import javax.lang.model.element.Modifier;
2630
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
2731
import software.amazon.awssdk.codegen.model.intermediate.MemberModel;
2832
import software.amazon.awssdk.codegen.model.intermediate.ShapeModel;
@@ -37,14 +41,18 @@ class NonCollectionSetters extends AbstractMemberSetters {
3741

3842
public List<MethodSpec> fluentDeclarations(TypeName returnType) {
3943
List<MethodSpec> fluentDeclarations = new ArrayList<>();
40-
fluentDeclarations.add(fluentSetterDeclaration(memberAsParameter(), returnType)
41-
.addJavadoc("$L", memberModel().getFluentSetterDocumentation())
42-
.build());
44+
fluentDeclarations.add(fluentAbstractSetterDeclaration(memberAsParameter(), returnType)
45+
.addJavadoc("$L", memberModel().getFluentSetterDocumentation())
46+
.build());
4347

4448
if (memberModel().getEnumType() != null) {
45-
fluentDeclarations.add(fluentSetterDeclaration(modeledParam(), returnType)
46-
.addJavadoc("$L", memberModel().getFluentSetterDocumentation())
47-
.build());
49+
fluentDeclarations.add(fluentAbstractSetterDeclaration(modeledParam(), returnType)
50+
.addJavadoc("$L", memberModel().getFluentSetterDocumentation())
51+
.build());
52+
}
53+
54+
if (memberModel().hasBuilder()) {
55+
fluentDeclarations.add(fluentConsumerFluentSetter(returnType));
4856
}
4957

5058
return fluentDeclarations;
@@ -79,23 +87,40 @@ public MethodSpec beanStyle() {
7987

8088
private MethodSpec fluentAssignmentSetter(TypeName returnType) {
8189
return fluentSetterBuilder(returnType)
82-
.addCode(copySetterBody().toBuilder().addStatement("return this").build())
83-
.build();
90+
.addCode(copySetterBody().toBuilder().addStatement("return this").build())
91+
.build();
8492
}
8593

8694
private MethodSpec fluentEnumToStringSetter(TypeName returnType) {
8795
return fluentSetterBuilder(modeledParam(), returnType)
88-
.addCode(enumToStringAssignmentBody().toBuilder().addStatement("return this").build())
89-
.build();
96+
.addCode(enumToStringAssignmentBody().toBuilder().addStatement("return this").build())
97+
.build();
98+
}
99+
100+
private MethodSpec fluentConsumerFluentSetter(TypeName returnType) {
101+
ClassName memberClass = poetExtensions.getModelClass(memberModel().getShape().getC2jName());
102+
ClassName builderClass = memberClass.nestedClass("Builder");
103+
return fluentDefaultSetterDeclaration(builderConsumerParam(builderClass), returnType)
104+
.addModifiers(Modifier.DEFAULT)
105+
.addStatement("return $N($T.builder().apply($N).build())",
106+
memberModel().getFluentSetterMethodName(),
107+
memberClass,
108+
fieldName())
109+
.addJavadoc("$L", memberModel().getDefaultConsumerFluentSetterDocumentation())
110+
.build();
90111
}
91112

92113
private CodeBlock enumToStringAssignmentBody() {
93114
return CodeBlock.builder()
94-
.addStatement("this.$N($N.toString())", fieldName(), fieldName())
95-
.build();
115+
.addStatement("this.$N($N.toString())", fieldName(), fieldName())
116+
.build();
96117
}
97118

98119
private ParameterSpec modeledParam() {
99120
return ParameterSpec.builder(poetExtensions.getModelClass(memberModel().getShape().getShapeName()), fieldName()).build();
100121
}
122+
123+
private ParameterSpec builderConsumerParam(ClassName builderClass) {
124+
return ParameterSpec.builder(ParameterizedTypeName.get(ClassName.get(Consumer.class), builderClass), fieldName()).build();
125+
}
101126
}

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

Lines changed: 96 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import java.util.Map;
99
import java.util.Objects;
1010
import java.util.Optional;
11+
import java.util.function.Consumer;
1112
import java.util.function.Function;
1213
import java.util.stream.Collectors;
1314
import javax.annotation.Generated;
@@ -450,7 +451,8 @@ public SubTypeOne polymorphicTypeWithoutSubTypes() {
450451
* Returns the value of the EnumType property for this object.
451452
* <p>
452453
* If the service returns an enum value that is not available in the current SDK version, {@link #enumType} will
453-
* return {@link EnumType#UNKNOWN_TO_SDK_VERSION}. The raw value returned by the service is available from {@link #enumTypeString}.
454+
* return {@link EnumType#UNKNOWN_TO_SDK_VERSION}. The raw value returned by the service is available from
455+
* {@link #enumTypeString}.
454456
* </p>
455457
*
456458
* @return The value of the EnumType property for this object.
@@ -464,7 +466,8 @@ public EnumType enumType() {
464466
* Returns the value of the EnumType property for this object.
465467
* <p>
466468
* If the service returns an enum value that is not available in the current SDK version, {@link #enumType} will
467-
* return {@link EnumType#UNKNOWN_TO_SDK_VERSION}. The raw value returned by the service is available from {@link #enumTypeString}.
469+
* return {@link EnumType#UNKNOWN_TO_SDK_VERSION}. The raw value returned by the service is available from
470+
* {@link #enumTypeString}.
468471
* </p>
469472
*
470473
* @return The value of the EnumType property for this object.
@@ -1063,6 +1066,24 @@ public interface Builder extends CopyableBuilder<Builder, AllTypesRequest> {
10631066
*/
10641067
Builder structWithNestedTimestampMember(StructWithTimestamp structWithNestedTimestampMember);
10651068

1069+
/**
1070+
* Sets the value of the StructWithNestedTimestampMember property for this object.
1071+
*
1072+
* This is a convenience that creates an instance of the {@link StructWithTimestamp.Builder} avoiding the need
1073+
* to create one manually via {@link StructWithTimestamp#builder()}.
1074+
*
1075+
* When the {@link Consumer} completes, {@link StructWithTimestamp.Builder#build()} is called immediately and
1076+
* its result is passed to {@link #structWithNestedTimestampMember(StructWithTimestamp)}.
1077+
*
1078+
* @param structWithNestedTimestampMember
1079+
* a consumer that will call methods on {@link StructWithTimestamp.Builder}
1080+
* @return Returns a reference to this object so that method calls can be chained together.
1081+
* @see #structWithNestedTimestampMember(StructWithTimestamp)
1082+
*/
1083+
default Builder structWithNestedTimestampMember(Consumer<StructWithTimestamp.Builder> structWithNestedTimestampMember) {
1084+
return structWithNestedTimestampMember(StructWithTimestamp.builder().apply(structWithNestedTimestampMember).build());
1085+
}
1086+
10661087
/**
10671088
* Sets the value of the BlobArg property for this object.
10681089
* <p>
@@ -1085,6 +1106,24 @@ public interface Builder extends CopyableBuilder<Builder, AllTypesRequest> {
10851106
*/
10861107
Builder structWithNestedBlob(StructWithNestedBlobType structWithNestedBlob);
10871108

1109+
/**
1110+
* Sets the value of the StructWithNestedBlob property for this object.
1111+
*
1112+
* This is a convenience that creates an instance of the {@link StructWithNestedBlobType.Builder} avoiding the
1113+
* need to create one manually via {@link StructWithNestedBlobType#builder()}.
1114+
*
1115+
* When the {@link Consumer} completes, {@link StructWithNestedBlobType.Builder#build()} is called immediately
1116+
* and its result is passed to {@link #structWithNestedBlob(StructWithNestedBlobType)}.
1117+
*
1118+
* @param structWithNestedBlob
1119+
* a consumer that will call methods on {@link StructWithNestedBlobType.Builder}
1120+
* @return Returns a reference to this object so that method calls can be chained together.
1121+
* @see #structWithNestedBlob(StructWithNestedBlobType)
1122+
*/
1123+
default Builder structWithNestedBlob(Consumer<StructWithNestedBlobType.Builder> structWithNestedBlob) {
1124+
return structWithNestedBlob(StructWithNestedBlobType.builder().apply(structWithNestedBlob).build());
1125+
}
1126+
10881127
/**
10891128
* Sets the value of the BlobMap property for this object.
10901129
*
@@ -1121,6 +1160,24 @@ public interface Builder extends CopyableBuilder<Builder, AllTypesRequest> {
11211160
*/
11221161
Builder recursiveStruct(RecursiveStructType recursiveStruct);
11231162

1163+
/**
1164+
* Sets the value of the RecursiveStruct property for this object.
1165+
*
1166+
* This is a convenience that creates an instance of the {@link RecursiveStructType.Builder} avoiding the need
1167+
* to create one manually via {@link RecursiveStructType#builder()}.
1168+
*
1169+
* When the {@link Consumer} completes, {@link RecursiveStructType.Builder#build()} is called immediately and
1170+
* its result is passed to {@link #recursiveStruct(RecursiveStructType)}.
1171+
*
1172+
* @param recursiveStruct
1173+
* a consumer that will call methods on {@link RecursiveStructType.Builder}
1174+
* @return Returns a reference to this object so that method calls can be chained together.
1175+
* @see #recursiveStruct(RecursiveStructType)
1176+
*/
1177+
default Builder recursiveStruct(Consumer<RecursiveStructType.Builder> recursiveStruct) {
1178+
return recursiveStruct(RecursiveStructType.builder().apply(recursiveStruct).build());
1179+
}
1180+
11241181
/**
11251182
* Sets the value of the PolymorphicTypeWithSubTypes property for this object.
11261183
*
@@ -1130,6 +1187,24 @@ public interface Builder extends CopyableBuilder<Builder, AllTypesRequest> {
11301187
*/
11311188
Builder polymorphicTypeWithSubTypes(BaseType polymorphicTypeWithSubTypes);
11321189

1190+
/**
1191+
* Sets the value of the PolymorphicTypeWithSubTypes property for this object.
1192+
*
1193+
* This is a convenience that creates an instance of the {@link BaseType.Builder} avoiding the need to create
1194+
* one manually via {@link BaseType#builder()}.
1195+
*
1196+
* When the {@link Consumer} completes, {@link BaseType.Builder#build()} is called immediately and its result is
1197+
* passed to {@link #polymorphicTypeWithSubTypes(BaseType)}.
1198+
*
1199+
* @param polymorphicTypeWithSubTypes
1200+
* a consumer that will call methods on {@link BaseType.Builder}
1201+
* @return Returns a reference to this object so that method calls can be chained together.
1202+
* @see #polymorphicTypeWithSubTypes(BaseType)
1203+
*/
1204+
default Builder polymorphicTypeWithSubTypes(Consumer<BaseType.Builder> polymorphicTypeWithSubTypes) {
1205+
return polymorphicTypeWithSubTypes(BaseType.builder().apply(polymorphicTypeWithSubTypes).build());
1206+
}
1207+
11331208
/**
11341209
* Sets the value of the PolymorphicTypeWithoutSubTypes property for this object.
11351210
*
@@ -1139,6 +1214,24 @@ public interface Builder extends CopyableBuilder<Builder, AllTypesRequest> {
11391214
*/
11401215
Builder polymorphicTypeWithoutSubTypes(SubTypeOne polymorphicTypeWithoutSubTypes);
11411216

1217+
/**
1218+
* Sets the value of the PolymorphicTypeWithoutSubTypes property for this object.
1219+
*
1220+
* This is a convenience that creates an instance of the {@link SubTypeOne.Builder} avoiding the need to create
1221+
* one manually via {@link SubTypeOne#builder()}.
1222+
*
1223+
* When the {@link Consumer} completes, {@link SubTypeOne.Builder#build()} is called immediately and its result
1224+
* is passed to {@link #polymorphicTypeWithoutSubTypes(SubTypeOne)}.
1225+
*
1226+
* @param polymorphicTypeWithoutSubTypes
1227+
* a consumer that will call methods on {@link SubTypeOne.Builder}
1228+
* @return Returns a reference to this object so that method calls can be chained together.
1229+
* @see #polymorphicTypeWithoutSubTypes(SubTypeOne)
1230+
*/
1231+
default Builder polymorphicTypeWithoutSubTypes(Consumer<SubTypeOne.Builder> polymorphicTypeWithoutSubTypes) {
1232+
return polymorphicTypeWithoutSubTypes(SubTypeOne.builder().apply(polymorphicTypeWithoutSubTypes).build());
1233+
}
1234+
11421235
/**
11431236
* Sets the value of the EnumType property for this object.
11441237
*
@@ -1545,7 +1638,7 @@ public final Builder structWithNestedTimestampMember(StructWithTimestamp structW
15451638

15461639
public final void setStructWithNestedTimestampMember(StructWithTimestamp.BuilderImpl structWithNestedTimestampMember) {
15471640
this.structWithNestedTimestampMember = structWithNestedTimestampMember != null ? structWithNestedTimestampMember
1548-
.build() : null;
1641+
.build() : null;
15491642
}
15501643

15511644
public final ByteBuffer getBlobArg() {

0 commit comments

Comments
 (0)