Skip to content

Implementing Consumer<Builder> fluent setters on model builders. #278

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -377,33 +377,56 @@ private boolean returnTypeIs(Class<?> clazz) {
}

public String getFluentSetterDocumentation() {
StringBuilder docBuilder = new StringBuilder();
docBuilder.append(getSetterDocumentation())
.append(LF)
.append("@return " + stripHtmlTags(DEFAULT_FLUENT_RETURN))
.append(getEnumDoc());
return docBuilder.toString();
return getSetterDocumentation()
+ LF
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does LF abbr stand for (saw the member declaration)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line-feed

+ "@return " + stripHtmlTags(DEFAULT_FLUENT_RETURN)
+ getEnumDoc();
}

public String getDefaultConsumerFluentSetterDocumentation() {
return (StringUtils.isNotBlank(documentation) ? documentation : DEFAULT_SETTER.replace("%s", name) + "\n")
+ LF
+ "This is a convenience that creates an instance of the {@link "
+ variable.getSimpleType()
+ ".Builder} avoiding the need to create one manually via {@link "
+ variable.getSimpleType()
+ "#builder()}.\n"
+ LF
+ "When the {@link Consumer} completes, {@link "
+ variable.getSimpleType()
+ ".Builder#build()} is called immediately and its result is passed to {@link #"
+ getFluentGetterMethodName()
+ "("
+ variable.getSimpleType()
+ ")}."
+ LF
+ "@param "
+ variable.getVariableName()
+ " a consumer that will call methods on {@link "
+ variable.getSimpleType() + ".Builder}"
+ LF
+ "@return " + stripHtmlTags(DEFAULT_FLUENT_RETURN)
+ LF
+ "@see #"
+ getFluentSetterMethodName()
+ "("
+ variable.getSimpleType()
+ ")";
}

private String getParamDoc() {
StringBuilder docBuilder = new StringBuilder();

String variableDesc = StringUtils.isNotBlank(documentation) ? documentation : DEFAULT_SETTER_PARAM.replace("%s", name);

docBuilder.append(LF)
.append("@param ")
.append(variable.getVariableName())
.append(" ")
.append(stripHtmlTags(variableDesc));
return docBuilder.toString();
return LF
+ "@param "
+ variable.getVariableName()
+ " "
+ stripHtmlTags(StringUtils.isNotBlank(documentation) ? documentation : DEFAULT_SETTER_PARAM.replace("%s", name));
}

private String getEnumDoc() {
StringBuilder docBuilder = new StringBuilder();

if (enumType != null) {
docBuilder.append(LF);
docBuilder.append("@see " + enumType);
docBuilder.append(LF).append("@see ").append(enumType);
}

return docBuilder.toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,12 @@ abstract class AbstractMemberSetters implements MemberSetters {
this.poetExtensions = new PoetExtensions(intermediateModel);
}

protected MethodSpec.Builder fluentSetterDeclaration(ParameterSpec parameter, TypeName returnType) {
return MethodSpec.methodBuilder(memberModel().getFluentSetterMethodName())
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.addParameter(parameter)
.returns(returnType);
protected MethodSpec.Builder fluentAbstractSetterDeclaration(ParameterSpec parameter, TypeName returnType) {
return fluentSetterDeclaration(parameter, returnType).addModifiers(Modifier.ABSTRACT);
}

protected MethodSpec.Builder fluentDefaultSetterDeclaration(ParameterSpec parameter, TypeName returnType) {
return fluentSetterDeclaration(parameter, returnType).addModifiers(Modifier.DEFAULT);
}

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

private MethodSpec.Builder fluentSetterDeclaration(ParameterSpec parameter, TypeName returnType) {
return MethodSpec.methodBuilder(memberModel().getFluentSetterMethodName())
.addModifiers(Modifier.PUBLIC)
.addParameter(parameter)
.returns(returnType);
}

private CodeBlock copySetterBody(String copyAssignment, String regularAssignment, String copyMethodName) {
Optional<ClassName> copierClass = serviceModelCopiers.copierClassFor(memberModel);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,17 @@ public List<MethodSpec> fluentDeclarations(TypeName returnType) {

String setterDocumentation = memberModel().getFluentSetterDocumentation();

fluentDeclarations.add(fluentSetterDeclaration(memberAsParameter(), returnType)
fluentDeclarations.add(fluentAbstractSetterDeclaration(memberAsParameter(), returnType)
.addJavadoc("$L", setterDocumentation)
.build());

fluentDeclarations.add(fluentSetterDeclaration(ParameterSpec.builder(asArray(), fieldName()).build(), returnType)
fluentDeclarations.add(fluentAbstractSetterDeclaration(ParameterSpec.builder(asArray(), fieldName()).build(), returnType)
.addJavadoc("$L", setterDocumentation)
.varargs(true)
.build());

if (memberModel().getEnumType() != null) {
fluentDeclarations.add(fluentSetterDeclaration(ParameterSpec.builder(
fluentDeclarations.add(fluentAbstractSetterDeclaration(ParameterSpec.builder(
asArrayOfModeledEnum(), fieldName()).build(), returnType)
.varargs(true)
.addJavadoc("$L", setterDocumentation)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class MapSetters extends AbstractMemberSetters {
}

public List<MethodSpec> fluentDeclarations(TypeName returnType) {
return Collections.singletonList(fluentSetterDeclaration(memberAsParameter(), returnType)
return Collections.singletonList(fluentAbstractSetterDeclaration(memberAsParameter(), returnType)
.addJavadoc("$L", memberModel().getFluentSetterDocumentation())
.build());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@

import com.fasterxml.jackson.annotation.JsonProperty;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import javax.lang.model.element.Modifier;
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
import software.amazon.awssdk.codegen.model.intermediate.MemberModel;
import software.amazon.awssdk.codegen.model.intermediate.ShapeModel;
Expand All @@ -37,14 +41,18 @@ class NonCollectionSetters extends AbstractMemberSetters {

public List<MethodSpec> fluentDeclarations(TypeName returnType) {
List<MethodSpec> fluentDeclarations = new ArrayList<>();
fluentDeclarations.add(fluentSetterDeclaration(memberAsParameter(), returnType)
.addJavadoc("$L", memberModel().getFluentSetterDocumentation())
.build());
fluentDeclarations.add(fluentAbstractSetterDeclaration(memberAsParameter(), returnType)
.addJavadoc("$L", memberModel().getFluentSetterDocumentation())
.build());

if (memberModel().getEnumType() != null) {
fluentDeclarations.add(fluentSetterDeclaration(modeledParam(), returnType)
.addJavadoc("$L", memberModel().getFluentSetterDocumentation())
.build());
fluentDeclarations.add(fluentAbstractSetterDeclaration(modeledParam(), returnType)
.addJavadoc("$L", memberModel().getFluentSetterDocumentation())
.build());
}

if (memberModel().hasBuilder()) {
fluentDeclarations.add(fluentConsumerFluentSetter(returnType));
}

return fluentDeclarations;
Expand Down Expand Up @@ -79,23 +87,40 @@ public MethodSpec beanStyle() {

private MethodSpec fluentAssignmentSetter(TypeName returnType) {
return fluentSetterBuilder(returnType)
.addCode(copySetterBody().toBuilder().addStatement("return this").build())
.build();
.addCode(copySetterBody().toBuilder().addStatement("return this").build())
.build();
}

private MethodSpec fluentEnumToStringSetter(TypeName returnType) {
return fluentSetterBuilder(modeledParam(), returnType)
.addCode(enumToStringAssignmentBody().toBuilder().addStatement("return this").build())
.build();
.addCode(enumToStringAssignmentBody().toBuilder().addStatement("return this").build())
.build();
}

private MethodSpec fluentConsumerFluentSetter(TypeName returnType) {
ClassName memberClass = poetExtensions.getModelClass(memberModel().getShape().getC2jName());
ClassName builderClass = memberClass.nestedClass("Builder");
return fluentDefaultSetterDeclaration(builderConsumerParam(builderClass), returnType)
.addModifiers(Modifier.DEFAULT)
.addStatement("return $N($T.builder().apply($N).build())",
memberModel().getFluentSetterMethodName(),
memberClass,
fieldName())
.addJavadoc("$L", memberModel().getDefaultConsumerFluentSetterDocumentation())
.build();
}

private CodeBlock enumToStringAssignmentBody() {
return CodeBlock.builder()
.addStatement("this.$N($N.toString())", fieldName(), fieldName())
.build();
.addStatement("this.$N($N.toString())", fieldName(), fieldName())
.build();
}

private ParameterSpec modeledParam() {
return ParameterSpec.builder(poetExtensions.getModelClass(memberModel().getShape().getShapeName()), fieldName()).build();
}

private ParameterSpec builderConsumerParam(ClassName builderClass) {
return ParameterSpec.builder(ParameterizedTypeName.get(ClassName.get(Consumer.class), builderClass), fieldName()).build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.Generated;
Expand Down Expand Up @@ -450,7 +451,8 @@ public SubTypeOne polymorphicTypeWithoutSubTypes() {
* Returns the value of the EnumType property for this object.
* <p>
* If the service returns an enum value that is not available in the current SDK version, {@link #enumType} will
* return {@link EnumType#UNKNOWN_TO_SDK_VERSION}. The raw value returned by the service is available from {@link #enumTypeString}.
* return {@link EnumType#UNKNOWN_TO_SDK_VERSION}. The raw value returned by the service is available from
* {@link #enumTypeString}.
* </p>
*
* @return The value of the EnumType property for this object.
Expand All @@ -464,7 +466,8 @@ public EnumType enumType() {
* Returns the value of the EnumType property for this object.
* <p>
* If the service returns an enum value that is not available in the current SDK version, {@link #enumType} will
* return {@link EnumType#UNKNOWN_TO_SDK_VERSION}. The raw value returned by the service is available from {@link #enumTypeString}.
* return {@link EnumType#UNKNOWN_TO_SDK_VERSION}. The raw value returned by the service is available from
* {@link #enumTypeString}.
* </p>
*
* @return The value of the EnumType property for this object.
Expand Down Expand Up @@ -1063,6 +1066,24 @@ public interface Builder extends CopyableBuilder<Builder, AllTypesRequest> {
*/
Builder structWithNestedTimestampMember(StructWithTimestamp structWithNestedTimestampMember);

/**
* Sets the value of the StructWithNestedTimestampMember property for this object.
*
* This is a convenience that creates an instance of the {@link StructWithTimestamp.Builder} avoiding the need
* to create one manually via {@link StructWithTimestamp#builder()}.
*
* When the {@link Consumer} completes, {@link StructWithTimestamp.Builder#build()} is called immediately and
* its result is passed to {@link #structWithNestedTimestampMember(StructWithTimestamp)}.
*
* @param structWithNestedTimestampMember
* a consumer that will call methods on {@link StructWithTimestamp.Builder}
* @return Returns a reference to this object so that method calls can be chained together.
* @see #structWithNestedTimestampMember(StructWithTimestamp)
*/
default Builder structWithNestedTimestampMember(Consumer<StructWithTimestamp.Builder> structWithNestedTimestampMember) {
return structWithNestedTimestampMember(StructWithTimestamp.builder().apply(structWithNestedTimestampMember).build());
}

/**
* Sets the value of the BlobArg property for this object.
* <p>
Expand All @@ -1085,6 +1106,24 @@ public interface Builder extends CopyableBuilder<Builder, AllTypesRequest> {
*/
Builder structWithNestedBlob(StructWithNestedBlobType structWithNestedBlob);

/**
* Sets the value of the StructWithNestedBlob property for this object.
*
* This is a convenience that creates an instance of the {@link StructWithNestedBlobType.Builder} avoiding the
* need to create one manually via {@link StructWithNestedBlobType#builder()}.
*
* When the {@link Consumer} completes, {@link StructWithNestedBlobType.Builder#build()} is called immediately
* and its result is passed to {@link #structWithNestedBlob(StructWithNestedBlobType)}.
*
* @param structWithNestedBlob
* a consumer that will call methods on {@link StructWithNestedBlobType.Builder}
* @return Returns a reference to this object so that method calls can be chained together.
* @see #structWithNestedBlob(StructWithNestedBlobType)
*/
default Builder structWithNestedBlob(Consumer<StructWithNestedBlobType.Builder> structWithNestedBlob) {
return structWithNestedBlob(StructWithNestedBlobType.builder().apply(structWithNestedBlob).build());
}

/**
* Sets the value of the BlobMap property for this object.
*
Expand Down Expand Up @@ -1121,6 +1160,24 @@ public interface Builder extends CopyableBuilder<Builder, AllTypesRequest> {
*/
Builder recursiveStruct(RecursiveStructType recursiveStruct);

/**
* Sets the value of the RecursiveStruct property for this object.
*
* This is a convenience that creates an instance of the {@link RecursiveStructType.Builder} avoiding the need
* to create one manually via {@link RecursiveStructType#builder()}.
*
* When the {@link Consumer} completes, {@link RecursiveStructType.Builder#build()} is called immediately and
* its result is passed to {@link #recursiveStruct(RecursiveStructType)}.
*
* @param recursiveStruct
* a consumer that will call methods on {@link RecursiveStructType.Builder}
* @return Returns a reference to this object so that method calls can be chained together.
* @see #recursiveStruct(RecursiveStructType)
*/
default Builder recursiveStruct(Consumer<RecursiveStructType.Builder> recursiveStruct) {
return recursiveStruct(RecursiveStructType.builder().apply(recursiveStruct).build());
}

/**
* Sets the value of the PolymorphicTypeWithSubTypes property for this object.
*
Expand All @@ -1130,6 +1187,24 @@ public interface Builder extends CopyableBuilder<Builder, AllTypesRequest> {
*/
Builder polymorphicTypeWithSubTypes(BaseType polymorphicTypeWithSubTypes);

/**
* Sets the value of the PolymorphicTypeWithSubTypes property for this object.
*
* This is a convenience that creates an instance of the {@link BaseType.Builder} avoiding the need to create
* one manually via {@link BaseType#builder()}.
*
* When the {@link Consumer} completes, {@link BaseType.Builder#build()} is called immediately and its result is
* passed to {@link #polymorphicTypeWithSubTypes(BaseType)}.
*
* @param polymorphicTypeWithSubTypes
* a consumer that will call methods on {@link BaseType.Builder}
* @return Returns a reference to this object so that method calls can be chained together.
* @see #polymorphicTypeWithSubTypes(BaseType)
*/
default Builder polymorphicTypeWithSubTypes(Consumer<BaseType.Builder> polymorphicTypeWithSubTypes) {
return polymorphicTypeWithSubTypes(BaseType.builder().apply(polymorphicTypeWithSubTypes).build());
}

/**
* Sets the value of the PolymorphicTypeWithoutSubTypes property for this object.
*
Expand All @@ -1139,6 +1214,24 @@ public interface Builder extends CopyableBuilder<Builder, AllTypesRequest> {
*/
Builder polymorphicTypeWithoutSubTypes(SubTypeOne polymorphicTypeWithoutSubTypes);

/**
* Sets the value of the PolymorphicTypeWithoutSubTypes property for this object.
*
* This is a convenience that creates an instance of the {@link SubTypeOne.Builder} avoiding the need to create
* one manually via {@link SubTypeOne#builder()}.
*
* When the {@link Consumer} completes, {@link SubTypeOne.Builder#build()} is called immediately and its result
* is passed to {@link #polymorphicTypeWithoutSubTypes(SubTypeOne)}.
*
* @param polymorphicTypeWithoutSubTypes
* a consumer that will call methods on {@link SubTypeOne.Builder}
* @return Returns a reference to this object so that method calls can be chained together.
* @see #polymorphicTypeWithoutSubTypes(SubTypeOne)
*/
default Builder polymorphicTypeWithoutSubTypes(Consumer<SubTypeOne.Builder> polymorphicTypeWithoutSubTypes) {
return polymorphicTypeWithoutSubTypes(SubTypeOne.builder().apply(polymorphicTypeWithoutSubTypes).build());
}

/**
* Sets the value of the EnumType property for this object.
*
Expand Down Expand Up @@ -1545,7 +1638,7 @@ public final Builder structWithNestedTimestampMember(StructWithTimestamp structW

public final void setStructWithNestedTimestampMember(StructWithTimestamp.BuilderImpl structWithNestedTimestampMember) {
this.structWithNestedTimestampMember = structWithNestedTimestampMember != null ? structWithNestedTimestampMember
.build() : null;
.build() : null;
}

public final ByteBuffer getBlobArg() {
Expand Down
Loading