Skip to content

Commit

Permalink
Return enums from model getters and make enums follow the standard java
Browse files Browse the repository at this point in the history
naming scheme.

Where appropriate, enums are now returned from model getters instead of
strings, which have been moved to a separate method that indicates its
value is a string.

Generated enums now follow the SCREAMING_CASE convention instead of the
PascalCase that was previously used.
  • Loading branch information
millems committed Oct 16, 2017
1 parent b23f261 commit f2a8b9b
Show file tree
Hide file tree
Showing 98 changed files with 1,947 additions and 580 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@
</Or>
<!-- URF_UNREAD_FIELD, DLS_DEAD_LOCAL_STORE: Sometimes we have unread variables and fields because they're only
conditionally used. It's cleaner to just always generate them, even if we may not actually be using them. -->
<Bug pattern="URF_UNREAD_FIELD,DLS_DEAD_LOCAL_STORE" />
<!-- REC_CATCH_EXCEPTION: Sometimes we want to convert runtime exceptions into sdk exceptions, so we catch it and
wrap it in an sdk-specific exception. -->
<Bug pattern="URF_UNREAD_FIELD,DLS_DEAD_LOCAL_STORE, REC_CATCH_EXCEPTION" />
</Match>
</FindBugsFilter>
59 changes: 20 additions & 39 deletions codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import static software.amazon.awssdk.codegen.internal.TypeUtils.MAP_INTERFACE;
import static software.amazon.awssdk.codegen.internal.TypeUtils.getDataTypeMapping;
import static software.amazon.awssdk.codegen.internal.Utils.capitialize;
import static software.amazon.awssdk.codegen.internal.Utils.isEnumShape;
import static software.amazon.awssdk.codegen.internal.Utils.isListShape;
import static software.amazon.awssdk.codegen.internal.Utils.isMapShape;
import static software.amazon.awssdk.codegen.internal.Utils.isScalar;
Expand All @@ -45,6 +44,7 @@
import software.amazon.awssdk.codegen.model.service.Shape;
import software.amazon.awssdk.codegen.naming.NamingStrategy;
import software.amazon.awssdk.utils.StringUtils;
import software.amazon.awssdk.utils.Validate;

abstract class AddShapes {

Expand Down Expand Up @@ -142,6 +142,7 @@ private MemberModel generateMemberModel(String c2jMemberName, Member c2jMemberDe
String protocol, Shape parentShape,
Map<String, Shape> allC2jShapes) {
final String c2jShapeName = c2jMemberDefinition.getShape();
final Shape c2jShape = allC2jShapes.get(c2jShapeName);
final String variableName = getNamingStrategy().getVariableName(c2jMemberName);
final String variableType = getTypeUtils().getJavaDataType(allC2jShapes, c2jShapeName);
final String variableDeclarationType = getTypeUtils()
Expand Down Expand Up @@ -169,7 +170,8 @@ private MemberModel generateMemberModel(String c2jMemberName, Member c2jMemberDe
memberModel.setDocumentation(c2jMemberDefinition.getDocumentation());
memberModel.setDeprecated(c2jMemberDefinition.isDeprecated());
memberModel
.withFluentGetterMethodName(namingStrategy.getFluentGetterMethodName(c2jMemberName))
.withFluentGetterMethodName(namingStrategy.getFluentGetterMethodName(c2jMemberName, c2jShape))
.withFluentEnumGetterMethodName(namingStrategy.getFluentEnumGetterMethodName(c2jMemberName, c2jShape))
.withFluentSetterMethodName(namingStrategy.getFluentSetterMethodName(c2jMemberName))
.withBeanStyleGetterMethodName(namingStrategy.getBeanStyleGetterMethodName(c2jMemberName))
.withBeanStyleSetterMethodName(namingStrategy.getBeanStyleSetterMethodName(c2jMemberName));
Expand All @@ -192,7 +194,7 @@ private MemberModel generateMemberModel(String c2jMemberName, Member c2jMemberDe

final String payload = parentShape.getPayload();

boolean shapeIsStreaming = allC2jShapes.get(c2jMemberDefinition.getShape()).isStreaming();
boolean shapeIsStreaming = c2jShape.isStreaming();
boolean memberIsStreaming = c2jMemberDefinition.isStreaming();
boolean payloadIsStreaming = shapeIsStreaming || memberIsStreaming;

Expand Down Expand Up @@ -294,48 +296,30 @@ private void fillContainerTypeMemberMetadata(Map<String, Shape> c2jShapes,
final Shape memberC2jShape = c2jShapes.get(memberC2jShapeName);

if (isListShape(memberC2jShape)) {

MemberModel listMemberModel;

Member listMemberDefinition = memberC2jShape.getListMember();
String listMemberC2jShapeName = listMemberDefinition.getShape();
Shape listMemberC2jShape = c2jShapes.get(listMemberC2jShapeName);

listMemberModel = generateMemberModel("member", listMemberDefinition, protocol,
memberC2jShape, c2jShapes);
MemberModel listMemberModel = generateMemberModel("member", listMemberDefinition, protocol,
memberC2jShape, c2jShapes);
final String listImpl = getDataTypeMapping(LIST_DEFAULT_IMPL);
memberModel.setListModel(
new ListModel(getTypeUtils().getJavaDataType(c2jShapes, listMemberC2jShapeName),
memberC2jShape.getListMember().getLocationName(), listImpl,
getDataTypeMapping(LIST_INTERFACE), listMemberModel));

if (listMemberC2jShape.getEnumValues() != null) {
memberModel
.setEnumType(getNamingStrategy().getJavaClassName(listMemberC2jShapeName));
}
} else if (isMapShape(memberC2jShape)) {

MemberModel mapKeyModel = null;
MemberModel mapValueModel;

Member mapKeyMemberDefinition = memberC2jShape.getMapKeyType();
String mapKeyShapeName = mapKeyMemberDefinition.getShape();
Shape mapKeyShape = c2jShapes.get(mapKeyShapeName);

Member mapValueMemberDefinition = memberC2jShape.getMapValueType();

// Only construct the nested key model if the key of the map
// itself is Enum shape. Throw exception if the nested key type is complex
// because we don't support complex map keys.
if (isEnumShape(mapKeyShape)) {
mapKeyModel = generateMemberModel("key", mapKeyMemberDefinition, protocol,
memberC2jShape, c2jShapes);
} else if (!isScalar(mapKeyShape)) {
throw new IllegalStateException(
"The key type of " + mapKeyShapeName + " must be a scalar!");
}
mapValueModel = generateMemberModel("value", mapValueMemberDefinition, protocol,
memberC2jShape, c2jShapes);
// Complex map keys are not supported.
Validate.isTrue(isScalar(mapKeyShape), "The key type of %s must be a scalar!", mapKeyShapeName);

MemberModel mapKeyModel = generateMemberModel("key", mapKeyMemberDefinition, protocol,
memberC2jShape, c2jShapes);
MemberModel mapValueModel = generateMemberModel("value", mapValueMemberDefinition, protocol,
memberC2jShape, c2jShapes);
final String mapImpl = getDataTypeMapping(MAP_DEFAULT_IMPL);

String keyLocation = memberC2jShape.getMapKeyType().getLocationName() != null ?
Expand All @@ -344,15 +328,12 @@ private void fillContainerTypeMemberMetadata(Map<String, Shape> c2jShapes,
String valueLocation = memberC2jShape.getMapValueType().getLocationName() != null ?
memberC2jShape.getMapValueType().getLocationName() : "value";

memberModel.setMapModel(new MapModel(mapImpl, getDataTypeMapping(MAP_INTERFACE),
getTypeUtils().getJavaDataType(c2jShapes,
memberC2jShape
.getMapKeyType()
.getShape()),
keyLocation, mapKeyModel, getTypeUtils()
.getJavaDataType(c2jShapes, memberC2jShape
.getMapValueType().getShape()),
valueLocation, mapValueModel));
memberModel.setMapModel(new MapModel(mapImpl,
getDataTypeMapping(MAP_INTERFACE),
keyLocation,
mapKeyModel,
valueLocation,
mapValueModel));

} else if (memberC2jShape.getEnumValues() != null) { // enum values
memberModel.withEnumType(getNamingStrategy().getJavaClassName(memberC2jShapeName));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import software.amazon.awssdk.codegen.model.config.customization.CustomizationConfig;
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
import software.amazon.awssdk.codegen.model.intermediate.MemberModel;
import software.amazon.awssdk.codegen.model.intermediate.Metadata;
import software.amazon.awssdk.codegen.model.intermediate.ShapeMarshaller;
import software.amazon.awssdk.codegen.model.intermediate.ShapeModel;
Expand Down Expand Up @@ -65,6 +67,22 @@ public static boolean isExceptionShape(Shape shape) {
return shape.isException() || shape.isFault();
}

public static boolean isOrContainsEnumShape(Shape shape, Map<String, Shape> allShapes) {
boolean isEnum = isEnumShape(shape);
boolean isMapWithEnumMember = isMapShape(shape) && (isEnumShape(allShapes.get(shape.getMapKeyType().getShape())) ||
isEnumShape(allShapes.get(shape.getMapValueType().getShape())));
boolean isListWithEnumMember = isListShape(shape) && isEnumShape(allShapes.get(shape.getListMember().getShape()));
return isEnum || isMapWithEnumMember || isListWithEnumMember;
}

public static boolean isOrContainsEnum(MemberModel member) {
boolean isEnum = member.getEnumType() != null;
boolean isMapWithEnumMember = member.isMap() && (member.getMapModel().getKeyModel().getEnumType() != null ||
member.getMapModel().getValueModel().getEnumType() != null);
boolean isListWithEnumMember = member.isList() && member.getListModel().getListMemberModel().getEnumType() != null;
return isEnum || isMapWithEnumMember || isListWithEnumMember;
}

public static String getServiceName(ServiceMetadata metadata, CustomizationConfig customizationConfig) {
String baseName = metadata.getServiceAbbreviation() == null ?
metadata.getServiceFullName() :
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,42 +16,33 @@
package software.amazon.awssdk.codegen.model.intermediate;

import com.fasterxml.jackson.annotation.JsonProperty;
import software.amazon.awssdk.codegen.internal.TypeUtils;

public class MapModel {

private final String implType;

private final String interfaceType;

private final String keyType;

private final String keyLocationName;

private final MemberModel keyModel;

private final String valueType;

private final String valueLocationName;

private final MemberModel valueModel;

public MapModel(
@JsonProperty("implType") String implType,
@JsonProperty("interfaceType") String interfaceType,
@JsonProperty("keyType") String mapKeyType,
@JsonProperty("keyLocationName") String keyLocationName,
@JsonProperty("keyModel") MemberModel keyModel,
@JsonProperty("valueType") String mapValueType,
@JsonProperty("valueLocationName") String valueLocationName,
@JsonProperty("valueModel") MemberModel valueModel) {

this.implType = implType;
this.interfaceType = interfaceType;
this.keyType = mapKeyType;
this.keyLocationName = keyLocationName;
this.keyModel = keyModel;
this.valueType = mapValueType;
this.valueLocationName = valueLocationName;
this.valueModel = valueModel;
}
Expand All @@ -64,10 +55,6 @@ public String getInterfaceType() {
return interfaceType;
}

public String getKeyType() {
return keyType;
}

public String getKeyLocationName() {
return keyLocationName;
}
Expand All @@ -76,10 +63,6 @@ public MemberModel getKeyModel() {
return keyModel;
}

public String getValueType() {
return valueType;
}

public String getValueLocationName() {
return valueLocationName;
}
Expand All @@ -88,28 +71,13 @@ public MemberModel getValueModel() {
return valueModel;
}

public boolean isKeySimple() {
return TypeUtils.isSimple(keyType);
}

public boolean isValueSimple() {
return TypeUtils.isSimple(valueType);
}

public boolean isValueList() {
return valueType.startsWith(TypeUtils
.getDataTypeMapping(TypeUtils.LIST_INTERFACE));
}

public String getTemplateType() {
return interfaceType + "<" + keyType + "," + valueType + ">";
}

public String getTemplateImplType() {
return implType + "<" + keyType + "," + valueType + ">";
return interfaceType +
"<" + keyModel.getVariable().getVariableType() + "," + valueModel.getVariable().getVariableType() + ">";
}

public String getEntryType() {
return String.format("Map.Entry<%s, %s>", keyType, valueType);
return String.format("Map.Entry<%s, %s>",
keyModel.getVariable().getVariableType(), valueModel.getVariable().getVariableType());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ public class MemberModel extends DocumentationModel {

private String fluentGetterMethodName;

private String fluentEnumGetterMethodName;

private String fluentSetterMethodName;

private String beanStyleGetterName;
Expand Down Expand Up @@ -148,6 +150,19 @@ public MemberModel withFluentGetterMethodName(String getterMethodName) {
return this;
}

public String getFluentEnumGetterMethodName() {
return fluentEnumGetterMethodName;
}

public void setFluentEnumGetterMethodName(String fluentEnumGetterMethodName) {
this.fluentEnumGetterMethodName = fluentEnumGetterMethodName;
}

public MemberModel withFluentEnumGetterMethodName(String fluentEnumGetterMethodName) {
setFluentEnumGetterMethodName(fluentEnumGetterMethodName);
return this;
}

public String getBeanStyleGetterMethodName() {
return beanStyleGetterName;
}
Expand Down Expand Up @@ -252,15 +267,15 @@ public void setListModel(ListModel listModel) {
this.listModel = listModel;
}

public MapModel getMapModel() {
return mapModel;
}

public MemberModel withListModel(ListModel list) {
setListModel(list);
return this;
}

public MapModel getMapModel() {
return mapModel;
}

public void setMapModel(MapModel map) {
this.mapModel = map;
}
Expand Down Expand Up @@ -301,7 +316,7 @@ public String getSetterDocumentation() {

docBuilder.append(StringUtils.isNotBlank(documentation) ? documentation : DEFAULT_SETTER.replace("%s", name) + "\n");

if (ByteBuffer.class.getName().equals(this.getGetterModel().getReturnType())) {
if (returnTypeIs(ByteBuffer.class)) {
appendParagraph(docBuilder, "To preserve immutability, the remaining bytes in the provided buffer will be copied "
+ "into a new buffer when set.");
}
Expand All @@ -313,20 +328,37 @@ public String getSetterDocumentation() {
}

public String getGetterDocumentation() {
String returnType = this.getGetterModel().getReturnType();
StringBuilder docBuilder = new StringBuilder();
docBuilder.append(StringUtils.isNotBlank(documentation) ? documentation : DEFAULT_GETTER.replace("%s", name))
.append(LF);

if (returnType != null) {
if (returnType.equals(ByteBuffer.class.getName())) {
appendParagraph(docBuilder,
"This method will return a new read-only {@code ByteBuffer} each time it is invoked.");
}
if (returnTypeIs(ByteBuffer.class)) {
appendParagraph(docBuilder,
"This method will return a new read-only {@code ByteBuffer} each time it is invoked.");
} else if (returnTypeIs(List.class) || returnTypeIs(Map.class)) {
appendParagraph(docBuilder, "Attempts to modify the collection returned by this method will result in an "
+ "UnsupportedOperationException.");
}

if (returnType.startsWith(List.class.getName()) || returnType.startsWith(Map.class.getName())) {
appendParagraph(docBuilder, "Attempts to modify the collection returned by this method will result in an "
+ "UnsupportedOperationException.");
if (enumType != null) {
if (returnTypeIs(List.class)) {
appendParagraph(docBuilder,
"If the list returned by the service includes enum values that are not available in the "
+ "current SDK version, {@link #%s} will use {@link %s#UNKNOWN_TO_SDK_VERSION} in place of those "
+ "values in the list. The raw values returned by the service are available from {@link #%s}.",
getFluentEnumGetterMethodName(), getEnumType(), getFluentGetterMethodName());
} else if (returnTypeIs(Map.class)) {
appendParagraph(docBuilder,
"If the map returned by the service includes enum values that are not available in the "
+ "current SDK version, {@link #%s} will not include those keys in the map. {@link #%s} "
+ "will include all data from the service.",
getFluentEnumGetterMethodName(), getEnumType(), getFluentGetterMethodName());
} else {
appendParagraph(docBuilder,
"If the service returns an enum value that is not available in the current SDK version, "
+ "{@link #%s} will return {@link %s#UNKNOWN_TO_SDK_VERSION}. The raw value returned by the "
+ "service is available from {@link #%s}.",
getFluentEnumGetterMethodName(), getEnumType(), getFluentGetterMethodName());
}
}

Expand All @@ -339,6 +371,11 @@ public String getGetterDocumentation() {
return docBuilder.toString();
}

private boolean returnTypeIs(Class<?> clazz) {
String returnType = this.getGetterModel().getReturnType();
return returnType != null && returnType.startsWith(clazz.getName()); // Use startsWith in case it's parametrized
}

public String getFluentSetterDocumentation() {
StringBuilder docBuilder = new StringBuilder();
docBuilder.append(getSetterDocumentation())
Expand Down Expand Up @@ -474,10 +511,10 @@ public String toString() {
return c2jName;
}

private void appendParagraph(StringBuilder builder, String content) {
private void appendParagraph(StringBuilder builder, String content, Object... contentArgs) {
builder.append("<p>")
.append(LF)
.append(content)
.append(String.format(content, contentArgs))
.append(LF)
.append("</p>")
.append(LF);
Expand Down
Loading

0 comments on commit f2a8b9b

Please sign in to comment.