Skip to content

Commit b9a2e77

Browse files
committed
Made code generation more resilient against bad method names.
When generating models that would collide with existing methods or use reserved words, rename the generated methods to end with 'Value' (e.g. ConfirmProductInstanceResult.return -> ConfirmProductInstanceResult.returnValue).
1 parent d7436c0 commit b9a2e77

File tree

16 files changed

+1072
-956
lines changed

16 files changed

+1072
-956
lines changed

codegen/src/main/java/software/amazon/awssdk/codegen/AddShapes.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ private MemberModel generateMemberModel(String c2jMemberName, Member c2jMemberDe
138138
String protocol, Shape parentShape,
139139
Map<String, Shape> allC2jShapes) {
140140
String c2jShapeName = c2jMemberDefinition.getShape();
141-
Shape c2jShape = allC2jShapes.get(c2jShapeName);
141+
Shape shape = allC2jShapes.get(c2jShapeName);
142142
String variableName = getNamingStrategy().getVariableName(c2jMemberName);
143143
String variableType = getTypeUtils().getJavaDataType(allC2jShapes, c2jShapeName);
144144
String variableDeclarationType = getTypeUtils()
@@ -163,17 +163,17 @@ private MemberModel generateMemberModel(String c2jMemberName, Member c2jMemberDe
163163
.withDocumentation(c2jMemberDefinition.getDocumentation()))
164164
.withSetterModel(new VariableModel(variableName, variableType, variableDeclarationType))
165165
.withGetterModel(new ReturnTypeModel(variableType))
166-
.withTimestampFormat(resolveTimestampFormat(c2jMemberDefinition, c2jShape))
166+
.withTimestampFormat(resolveTimestampFormat(c2jMemberDefinition, shape))
167167
.withJsonValue(c2jMemberDefinition.getJsonValue());
168168
memberModel.setDocumentation(c2jMemberDefinition.getDocumentation());
169169
memberModel.setDeprecated(c2jMemberDefinition.isDeprecated());
170170
memberModel
171-
.withFluentGetterMethodName(namingStrategy.getFluentGetterMethodName(c2jMemberName, c2jShape))
172-
.withFluentEnumGetterMethodName(namingStrategy.getFluentEnumGetterMethodName(c2jMemberName, c2jShape))
173-
.withFluentSetterMethodName(namingStrategy.getFluentSetterMethodName(c2jMemberName, c2jShape))
174-
.withFluentEnumSetterMethodName(namingStrategy.getFluentEnumSetterMethodName(c2jMemberName, c2jShape))
175-
.withBeanStyleGetterMethodName(namingStrategy.getBeanStyleGetterMethodName(c2jMemberName))
176-
.withBeanStyleSetterMethodName(namingStrategy.getBeanStyleSetterMethodName(c2jMemberName));
171+
.withFluentGetterMethodName(namingStrategy.getFluentGetterMethodName(c2jMemberName, parentShape, shape))
172+
.withFluentEnumGetterMethodName(namingStrategy.getFluentEnumGetterMethodName(c2jMemberName, parentShape, shape))
173+
.withFluentSetterMethodName(namingStrategy.getFluentSetterMethodName(c2jMemberName, parentShape, shape))
174+
.withFluentEnumSetterMethodName(namingStrategy.getFluentEnumSetterMethodName(c2jMemberName, parentShape, shape))
175+
.withBeanStyleGetterMethodName(namingStrategy.getBeanStyleGetterMethodName(c2jMemberName, parentShape, shape))
176+
.withBeanStyleSetterMethodName(namingStrategy.getBeanStyleSetterMethodName(c2jMemberName, parentShape, shape));
177177
memberModel.setIdempotencyToken(c2jMemberDefinition.isIdempotencyToken());
178178
memberModel.setEventPayload(c2jMemberDefinition.isEventPayload());
179179
memberModel.setEventHeader(c2jMemberDefinition.isEventHeader());
@@ -195,7 +195,7 @@ private MemberModel generateMemberModel(String c2jMemberName, Member c2jMemberDe
195195

196196
String payload = parentShape.getPayload();
197197

198-
boolean shapeIsStreaming = c2jShape.isStreaming();
198+
boolean shapeIsStreaming = shape.isStreaming();
199199
boolean memberIsStreaming = c2jMemberDefinition.isStreaming();
200200
boolean payloadIsStreaming = shapeIsStreaming || memberIsStreaming;
201201

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public final class Constant {
6666

6767
public static final String FAULT_CLASS_SUFFIX = "Fault";
6868

69-
public static final String VARIABLE_NAME_SUFFIX = "Value";
69+
public static final String CONFLICTING_NAME_SUFFIX = "Value";
7070

7171
public static final String AUTHORIZER_NAME_PREFIX = "I";
7272

codegen/src/main/java/software/amazon/awssdk/codegen/naming/DefaultNamingStrategy.java

Lines changed: 78 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@
1717

1818
import static java.util.stream.Collectors.joining;
1919
import static software.amazon.awssdk.codegen.internal.Constant.AUTHORIZER_NAME_PREFIX;
20+
import static software.amazon.awssdk.codegen.internal.Constant.CONFLICTING_NAME_SUFFIX;
2021
import static software.amazon.awssdk.codegen.internal.Constant.EXCEPTION_CLASS_SUFFIX;
2122
import static software.amazon.awssdk.codegen.internal.Constant.FAULT_CLASS_SUFFIX;
2223
import static software.amazon.awssdk.codegen.internal.Constant.REQUEST_CLASS_SUFFIX;
2324
import static software.amazon.awssdk.codegen.internal.Constant.RESPONSE_CLASS_SUFFIX;
24-
import static software.amazon.awssdk.codegen.internal.Constant.VARIABLE_NAME_SUFFIX;
2525
import static software.amazon.awssdk.codegen.internal.Utils.unCapitalize;
2626

2727
import java.util.Arrays;
@@ -50,16 +50,41 @@ public class DefaultNamingStrategy implements NamingStrategy {
5050

5151
private static final Set<String> RESERVED_KEYWORDS;
5252

53+
private static final Set<String> RESERVED_EXCEPTION_METHOD_NAMES;
54+
55+
private static final Set<Object> RESERVED_STRUCTURE_METHOD_NAMES;
56+
5357
static {
54-
Set<String> keywords = new HashSet<>();
55-
Collections.addAll(keywords,
58+
Set<String> reservedJavaKeywords = new HashSet<>();
59+
Collections.addAll(reservedJavaKeywords,
5660
"abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class",
57-
"continue", "default", "do", "double", "else", "enum", "extends", "final", "finally", "float", "for",
58-
"if", "implements", "import", "instanceof", "int", "interface", "long", "native", "new", "package",
59-
"private", "protected", "public", "return", "short", "static", "strictfp", "super", "switch",
60-
"synchronized", "this", "throw", "throws", "transient", "try", "void", "volatile", "while", "true",
61-
"null", "false", "const", "goto");
62-
RESERVED_KEYWORDS = Collections.unmodifiableSet(keywords);
61+
"const", "continue", "default", "do", "double", "else", "enum", "extends", "false", "final",
62+
"finally", "float", "for", "goto", "if", "implements", "import", "instanceof", "int",
63+
"interface", "long", "native", "new", "null", "package", "private", "protected", "public",
64+
"return", "short", "static", "strictfp", "super", "switch", "synchronized", "this", "throw",
65+
"throws", "transient", "true", "try", "void", "volatile", "while");
66+
RESERVED_KEYWORDS = Collections.unmodifiableSet(reservedJavaKeywords);
67+
68+
69+
Set<String> reservedJavaMethodNames = new HashSet<>();
70+
Collections.addAll(reservedJavaMethodNames,
71+
"equals", "finalize", "getClass", "hashCode", "notify", "notifyAll", "toString", "wait");
72+
73+
Set<String> reserveJavaPojoMethodNames = new HashSet<>(reservedJavaMethodNames);
74+
Collections.addAll(reserveJavaPojoMethodNames,
75+
"builder", "sdkFields", "toBuilder");
76+
77+
Set<String> reservedExceptionMethodNames = new HashSet<>(reserveJavaPojoMethodNames);
78+
Collections.addAll(reservedExceptionMethodNames,
79+
"awsErrorDetails", "cause", "fillInStackTrace", "getCause", "getLocalizedMessage",
80+
"getMessage", "getStackTrace", "getSuppressed", "isClockSkewException", "isThrottlingException",
81+
"printStackTrace", "requestId", "retryable", "serializableBuilderClass", "statusCode");
82+
RESERVED_EXCEPTION_METHOD_NAMES = Collections.unmodifiableSet(reservedExceptionMethodNames);
83+
84+
Set<String> reservedStructureMethodNames = new HashSet<>(reserveJavaPojoMethodNames);
85+
Collections.addAll(reservedStructureMethodNames,
86+
"overrideConfiguration", "sdkHttpResponse");
87+
RESERVED_STRUCTURE_METHOD_NAMES = Collections.unmodifiableSet(reservedStructureMethodNames);
6388
}
6489

6590
private final ServiceModel serviceModel;
@@ -189,11 +214,15 @@ public String getResponseClassName(String operationName) {
189214

190215
@Override
191216
public String getVariableName(String name) {
192-
if (isJavaKeyword(name)) {
193-
return unCapitalize(name + VARIABLE_NAME_SUFFIX);
194-
} else {
195-
return unCapitalize(name);
217+
// Exclude keywords because they will not compile, and exclude reserved method names because they're frequently
218+
// used for local variable names.
219+
if (RESERVED_KEYWORDS.contains(name) ||
220+
RESERVED_STRUCTURE_METHOD_NAMES.contains(name) ||
221+
RESERVED_EXCEPTION_METHOD_NAMES.contains(name)) {
222+
return unCapitalize(name + CONFLICTING_NAME_SUFFIX);
196223
}
224+
225+
return unCapitalize(name);
197226
}
198227

199228
@Override
@@ -236,9 +265,11 @@ public String getAuthorizerClassName(String shapeName) {
236265
}
237266

238267
@Override
239-
public String getFluentGetterMethodName(String memberName, Shape shape) {
268+
public String getFluentGetterMethodName(String memberName, Shape parentShape, Shape shape) {
240269
String getterMethodName = Utils.unCapitalize(memberName);
241270

271+
getterMethodName = rewriteInvalidMemberName(getterMethodName, parentShape);
272+
242273
if (Utils.isOrContainsEnumShape(shape, serviceModel.getShapes())) {
243274
getterMethodName += "AsString";
244275

@@ -251,33 +282,34 @@ public String getFluentGetterMethodName(String memberName, Shape shape) {
251282
}
252283

253284
@Override
254-
public String getFluentEnumGetterMethodName(String memberName, Shape shape) {
285+
public String getFluentEnumGetterMethodName(String memberName, Shape parentShape, Shape shape) {
255286
if (!Utils.isOrContainsEnumShape(shape, serviceModel.getShapes())) {
256287
return null;
257288
}
258289

259-
return Utils.unCapitalize(memberName);
260-
}
261-
262-
@Override
263-
public String getBeanStyleGetterMethodName(String memberName) {
264-
return String.format("get%s", Utils.capitalize(memberName));
290+
String getterMethodName = Utils.unCapitalize(memberName);
291+
getterMethodName = rewriteInvalidMemberName(getterMethodName, parentShape);
292+
return getterMethodName;
265293
}
266294

267295
@Override
268-
public String getSetterMethodName(String memberName) {
269-
return Utils.unCapitalize(memberName);
296+
public String getBeanStyleGetterMethodName(String memberName, Shape parentShape, Shape c2jShape) {
297+
String fluentGetterMethodName = getFluentGetterMethodName(memberName, parentShape, c2jShape);
298+
return String.format("get%s", Utils.capitalize(fluentGetterMethodName));
270299
}
271300

272301
@Override
273-
public String getBeanStyleSetterMethodName(String memberName) {
274-
return String.format("set%s", Utils.capitalize(memberName));
302+
public String getBeanStyleSetterMethodName(String memberName, Shape parentShape, Shape c2jShape) {
303+
String fluentSetterMethodName = getFluentSetterMethodName(memberName, parentShape, c2jShape);
304+
return String.format("set%s", Utils.capitalize(fluentSetterMethodName));
275305
}
276306

277307
@Override
278-
public String getFluentSetterMethodName(String memberName, Shape shape) {
308+
public String getFluentSetterMethodName(String memberName, Shape parentShape, Shape shape) {
279309
String setterMethodName = Utils.unCapitalize(memberName);
280310

311+
setterMethodName = rewriteInvalidMemberName(setterMethodName, parentShape);
312+
281313
if (Utils.isOrContainsEnumShape(shape, serviceModel.getShapes()) &&
282314
(Utils.isListShape(shape) || Utils.isMapShape(shape))) {
283315

@@ -288,19 +320,37 @@ public String getFluentSetterMethodName(String memberName, Shape shape) {
288320
}
289321

290322
@Override
291-
public String getFluentEnumSetterMethodName(String memberName, Shape shape) {
323+
public String getFluentEnumSetterMethodName(String memberName, Shape parentShape, Shape shape) {
292324
if (!Utils.isOrContainsEnumShape(shape, serviceModel.getShapes())) {
293325
return null;
294326
}
295327

296-
return Utils.unCapitalize(memberName);
328+
String setterMethodName = Utils.unCapitalize(memberName);
329+
setterMethodName = rewriteInvalidMemberName(setterMethodName, parentShape);
330+
return setterMethodName;
297331
}
298332

299333
@Override
300334
public String getSdkFieldFieldName(MemberModel memberModel) {
301335
return screamCase(memberModel.getName()) + "_FIELD";
302336
}
303337

338+
private String rewriteInvalidMemberName(String memberName, Shape parentShape) {
339+
if (isJavaKeyword(memberName) || isDisallowedNameForShape(memberName, parentShape)) {
340+
return Utils.unCapitalize(memberName + CONFLICTING_NAME_SUFFIX);
341+
}
342+
343+
return memberName;
344+
}
345+
346+
private boolean isDisallowedNameForShape(String name, Shape parentShape) {
347+
if (parentShape.isException()) {
348+
return RESERVED_EXCEPTION_METHOD_NAMES.contains(name);
349+
} else {
350+
return RESERVED_STRUCTURE_METHOD_NAMES.contains(name);
351+
}
352+
}
353+
304354
private String[] splitOnWordBoundaries(String toSplit) {
305355
String result = toSplit;
306356

codegen/src/main/java/software/amazon/awssdk/codegen/naming/NamingStrategy.java

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -105,45 +105,39 @@ public interface NamingStrategy {
105105
* @param shape The shape associated with the member.
106106
* @return Name of the getter method for a model class member.
107107
*/
108-
String getFluentGetterMethodName(String memberName, Shape shape);
108+
String getFluentGetterMethodName(String memberName, Shape parentShape, Shape shape);
109109

110110
/**
111111
* @param memberName The full member to get the name for.
112112
* @param shape The shape associated with the member.
113113
* @return Name of the getter method for an enum model class member.
114114
*/
115-
String getFluentEnumGetterMethodName(String memberName, Shape shape);
115+
String getFluentEnumGetterMethodName(String memberName, Shape parentShape, Shape shape);
116116

117117
/**
118118
* @param memberName Member name to name getter for.
119119
* @return Name of the JavaBean getter method for model class member.
120120
*/
121-
String getBeanStyleGetterMethodName(String memberName);
122-
123-
/**
124-
* @param memberName Member name to name setter for.
125-
* @return Name of the setter method for a model class member.
126-
*/
127-
String getSetterMethodName(String memberName);
121+
String getBeanStyleGetterMethodName(String memberName, Shape parentShape, Shape c2jShape);
128122

129123
/**
130124
* @param memberName Member name to name setter for.
131125
* @return Name of the JavaBean setter method for model class member.
132126
*/
133-
String getBeanStyleSetterMethodName(String memberName);
127+
String getBeanStyleSetterMethodName(String memberName, Shape parentShape, Shape c2jShape);
134128

135129
/**
136130
* @param memberName Member name to name fluent setter for.
137131
* @return Appropriate name to use for fluent setter method (i.e. withFoo) for a model class member.
138132
*/
139-
String getFluentSetterMethodName(String memberName, Shape shape);
133+
String getFluentSetterMethodName(String memberName, Shape parentShape, Shape shape);
140134

141135
/**
142136
* @param memberName The full member to get the name for.
143137
* @param shape The shape associated with the member.
144138
* @return Name of the getter method for an enum model class member.
145139
*/
146-
String getFluentEnumSetterMethodName(String memberName, Shape shape);
140+
String getFluentEnumSetterMethodName(String memberName, Shape parentShape, Shape shape);
147141

148142
/**
149143
* Stuttering is intentional, returns the name of the {@link SdkField} field.

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

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -124,33 +124,36 @@ protected CodeBlock copySetterBuilderBody() {
124124

125125
protected CodeBlock beanCopySetterBody() {
126126
if (memberModel.isSdkBytesType()) {
127-
return sdkBytesGetter();
127+
return sdkBytesSetter();
128128
}
129129
if (memberModel.isList() && memberModel.getListModel().getListMemberModel().isSdkBytesType()) {
130-
return sdkBytesListGetter();
130+
return sdkBytesListSetter();
131131
}
132132
if (memberModel.isMap() && memberModel.getMapModel().getValueModel().isSdkBytesType()) {
133-
return sdkBytesMapValueGetter();
133+
return sdkBytesMapValueSetter();
134134
}
135135

136136
return copySetterBuilderBody();
137137
}
138138

139-
private CodeBlock sdkBytesGetter() {
140-
return CodeBlock.of("$1N($1N == null ? null : $2T.fromByteBuffer($1N));",
141-
memberModel.getVariable().getVariableName(), SdkBytes.class);
139+
private CodeBlock sdkBytesSetter() {
140+
return CodeBlock.of("$1N($2N == null ? null : $3T.fromByteBuffer($2N));",
141+
memberModel.getFluentSetterMethodName(), fieldName(),
142+
SdkBytes.class);
142143
}
143144

144-
private CodeBlock sdkBytesListGetter() {
145-
return CodeBlock.of("$1N($1N == null ? null : $1N.stream().map($2T::fromByteBuffer).collect($3T.toList()));",
146-
memberModel.getVariable().getVariableName(), SdkBytes.class, Collectors.class);
145+
private CodeBlock sdkBytesListSetter() {
146+
return CodeBlock.of("$1N($2N == null ? null : $2N.stream().map($3T::fromByteBuffer).collect($4T.toList()));",
147+
memberModel.getFluentSetterMethodName(), fieldName(),
148+
SdkBytes.class, Collectors.class);
147149
}
148150

149-
private CodeBlock sdkBytesMapValueGetter() {
150-
return CodeBlock.of("$1N($1N == null ? null : " +
151-
"$1N.entrySet().stream()" +
152-
".collect($3T.toMap(e -> e.getKey(), e -> $2T.fromByteBuffer(e.getValue()))));",
153-
memberModel.getVariable().getVariableName(), SdkBytes.class, Collectors.class);
151+
private CodeBlock sdkBytesMapValueSetter() {
152+
return CodeBlock.of("$1N($2N == null ? null : " +
153+
"$2N.entrySet().stream()" +
154+
".collect($4T.toMap(e -> e.getKey(), e -> $3T.fromByteBuffer(e.getValue()))));",
155+
memberModel.getFluentSetterMethodName(), fieldName(),
156+
SdkBytes.class, Collectors.class);
154157
}
155158

156159
protected ParameterSpec memberAsParameter() {

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -179,16 +179,18 @@ private MethodSpec fluentEnumVarargToListSetter(String methodName,
179179

180180

181181
private CodeBlock varargToListSetterBody() {
182-
return CodeBlock.of("$1L($2T.asList($3L));", memberModel().getFluentSetterMethodName(), Arrays.class, fieldName());
182+
return CodeBlock.of("$1L($2T.asList($3L));",
183+
memberModel().getFluentSetterMethodName(), Arrays.class, fieldName());
183184
}
184185

185186
private CodeBlock consumerBuilderVarargSetterBody() {
186-
return CodeBlock.of("$1L($2T.of($1L).map(c -> $3T.builder().applyMutation(c).build()).collect($4T.toList()));",
187-
fieldName(), Stream.class, listElementType(), Collectors.class);
187+
return CodeBlock.of("$1L($3T.of($2L).map(c -> $4T.builder().applyMutation(c).build()).collect($5T.toList()));",
188+
memberModel().getFluentSetterMethodName(), fieldName(),
189+
Stream.class, listElementType(), Collectors.class);
188190
}
189191

190192
private CodeBlock enumVarargToListSetterBody() {
191-
return CodeBlock.of("$1L($2T.asList($1L));", fieldName(), Arrays.class);
193+
return CodeBlock.of("$1L($3T.asList($2L));", memberModel().getFluentEnumSetterMethodName(), fieldName(), Arrays.class);
192194
}
193195

194196
private MemberModel elementModel() {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ private MethodSpec fluentConsumerFluentSetter(TypeName returnType) {
130130

131131
private CodeBlock enumToStringAssignmentBody() {
132132
return CodeBlock.builder()
133-
.addStatement("this.$N($N.toString())", fieldName(), fieldName())
133+
.addStatement("this.$N($N.toString())", memberModel().getFluentSetterMethodName(), fieldName())
134134
.build();
135135
}
136136

0 commit comments

Comments
 (0)