Skip to content

Commit 417d0c5

Browse files
committed
Making exceptions immutable
1 parent 56ab06e commit 417d0c5

File tree

152 files changed

+2278
-1139
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

152 files changed

+2278
-1139
lines changed

codegen/src/main/java/software/amazon/awssdk/codegen/emitters/tasks/BaseExceptionClassGeneratorTasks.java

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@
1515

1616
package software.amazon.awssdk.codegen.emitters.tasks;
1717

18-
import java.util.Collections;
18+
import java.util.Arrays;
1919
import java.util.List;
20-
import software.amazon.awssdk.codegen.emitters.FreemarkerGeneratorTask;
20+
2121
import software.amazon.awssdk.codegen.emitters.GeneratorTask;
2222
import software.amazon.awssdk.codegen.emitters.GeneratorTaskParams;
23-
import software.amazon.awssdk.core.util.ImmutableMapParameter;
23+
import software.amazon.awssdk.codegen.emitters.PoetGeneratorTask;
24+
import software.amazon.awssdk.codegen.poet.model.BaseExceptionClass;
2425

2526
public class BaseExceptionClassGeneratorTasks extends BaseGeneratorTasks {
2627

@@ -36,23 +37,13 @@ public BaseExceptionClassGeneratorTasks(GeneratorTaskParams dependencies) {
3637
*/
3738
@Override
3839
protected boolean hasTasks() {
39-
4040
return model.getCustomizationConfig().getSdkModeledExceptionBaseClassName() == null;
4141
}
4242

4343
@Override
4444
protected List<GeneratorTask> createTasks() throws Exception {
4545
info("Emitting Base Service Exception class");
46-
final String baseClassName = model.getSdkModeledExceptionBaseClassName();
47-
return Collections.singletonList(
48-
new FreemarkerGeneratorTask(modelClassDir,
49-
baseClassName,
50-
freemarker.getBaseExceptionClassTemplate(),
51-
ImmutableMapParameter.of(
52-
"fileHeader", model.getFileHeader(),
53-
"className", baseClassName,
54-
"metadata", model.getMetadata(),
55-
"baseExceptionFqcn", model.getServiceBaseExceptionFqcn())));
46+
return Arrays.asList(new PoetGeneratorTask(modelClassDir, model.getFileHeader(), new BaseExceptionClass(model)));
5647
}
5748

5849
}

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,7 @@ public AwsServiceModel(IntermediateModel intermediateModel, ShapeModel shapeMode
6767
this.typeProvider = new TypeProvider(intermediateModel);
6868
this.shapeModelSpec = new ShapeModelSpec(this.shapeModel, typeProvider, poetExtensions);
6969
this.modelMethodOverrides = new ModelMethodOverrides(this.poetExtensions);
70-
this.modelBuilderSpecs = new ModelBuilderSpecs(intermediateModel, this.shapeModel, this.shapeModelSpec,
71-
this.typeProvider);
70+
this.modelBuilderSpecs = new ModelBuilderSpecs(intermediateModel, this.shapeModel, this.typeProvider);
7271
}
7372

7473
@Override
@@ -356,7 +355,7 @@ private MethodSpec exceptionConstructor() {
356355
.addModifiers(Modifier.PRIVATE)
357356
.addParameter(modelBuilderSpecs.builderImplName(), "builder");
358357

359-
ctorBuilder.addStatement("super(builder.message)");
358+
ctorBuilder.addStatement("super(builder)");
360359

361360
shapeModelSpec.fields().forEach(f -> ctorBuilder.addStatement("this.$N = builder.$N", f, f));
362361

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
* Copyright 2010-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.codegen.poet.model;
17+
18+
import com.squareup.javapoet.ClassName;
19+
import com.squareup.javapoet.MethodSpec;
20+
import com.squareup.javapoet.ParameterizedTypeName;
21+
import com.squareup.javapoet.TypeSpec;
22+
import com.squareup.javapoet.WildcardTypeName;
23+
24+
import javax.lang.model.element.Modifier;
25+
26+
import software.amazon.awssdk.awscore.exception.AwsServiceException;
27+
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
28+
import software.amazon.awssdk.codegen.poet.ClassSpec;
29+
import software.amazon.awssdk.codegen.poet.PoetUtils;
30+
31+
public class BaseExceptionClass implements ClassSpec {
32+
33+
private final ClassName baseExceptionClassName;
34+
35+
public BaseExceptionClass(IntermediateModel model) {
36+
final String basePackage = model.getMetadata().getFullModelPackageName();
37+
this.baseExceptionClassName = ClassName.get(basePackage, model.getSdkModeledExceptionBaseClassName());
38+
}
39+
40+
41+
@Override
42+
public TypeSpec poetSpec() {
43+
return PoetUtils.createClassBuilder(baseExceptionClassName)
44+
.superclass(AwsServiceException.class)
45+
.addMethod(constructor())
46+
.addMethod(builderMethod())
47+
.addMethod(toBuilderMethod())
48+
.addMethod(serializableBuilderClass())
49+
.addModifiers(Modifier.PUBLIC)
50+
.addType(builderInterface())
51+
.addType(builderImplClass())
52+
.build();
53+
}
54+
55+
public MethodSpec constructor() {
56+
return MethodSpec.constructorBuilder()
57+
.addModifiers(Modifier.PROTECTED)
58+
.addParameter(baseExceptionClassName.nestedClass("Builder"), "builder")
59+
.addStatement("super(builder)")
60+
.build();
61+
}
62+
63+
public TypeSpec builderInterface() {
64+
TypeSpec.Builder builder = TypeSpec.interfaceBuilder(baseExceptionClassName.nestedClass("Builder"))
65+
.addSuperinterface(ClassName.get(AwsServiceException.class).nestedClass("Builder"))
66+
.addModifiers(Modifier.PUBLIC)
67+
.addMethods(ExceptionProperties.builderInterfaceMethods(className().nestedClass("Builder")));
68+
69+
return builder.build();
70+
}
71+
72+
public TypeSpec builderImplClass() {
73+
return TypeSpec.classBuilder(baseExceptionClassName.nestedClass("BuilderImpl"))
74+
.addSuperinterface(className().nestedClass("Builder"))
75+
.superclass(ClassName.get(AwsServiceException.class).nestedClass("BuilderImpl"))
76+
.addModifiers(Modifier.STATIC, Modifier.PROTECTED)
77+
.addMethod(MethodSpec.constructorBuilder().addModifiers(Modifier.PROTECTED).build())
78+
.addMethod(copyModelConstructor())
79+
.addMethods(ExceptionProperties.builderImplMethods(className().nestedClass("BuilderImpl")))
80+
.addMethod(MethodSpec.methodBuilder("build")
81+
.addModifiers(Modifier.PUBLIC)
82+
.addStatement("return new $T(this)", className())
83+
.returns(className())
84+
.build())
85+
.build();
86+
}
87+
88+
private MethodSpec copyModelConstructor() {
89+
return MethodSpec.constructorBuilder()
90+
.addModifiers(Modifier.PROTECTED)
91+
.addParameter(className(), "ex")
92+
.addStatement("super(ex)")
93+
.build();
94+
}
95+
96+
private MethodSpec builderMethod() {
97+
return MethodSpec.methodBuilder("builder")
98+
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
99+
.returns(className().nestedClass("Builder"))
100+
.addStatement("return new $T()", className().nestedClass("BuilderImpl"))
101+
.build();
102+
}
103+
104+
private MethodSpec toBuilderMethod() {
105+
return MethodSpec.methodBuilder("toBuilder")
106+
.addModifiers(Modifier.PUBLIC)
107+
.addAnnotation(Override.class)
108+
.returns(className().nestedClass("Builder"))
109+
.addStatement("return new $T(this)", className().nestedClass("BuilderImpl"))
110+
.build();
111+
}
112+
113+
private MethodSpec serializableBuilderClass() {
114+
return MethodSpec.methodBuilder("serializableBuilderClass")
115+
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
116+
.returns(ParameterizedTypeName.get(ClassName.get(Class.class),
117+
WildcardTypeName.subtypeOf(className().nestedClass("Builder"))))
118+
.addStatement("return $T.class", className().nestedClass("BuilderImpl"))
119+
.build();
120+
}
121+
122+
@Override
123+
public ClassName className() {
124+
return baseExceptionClassName;
125+
}
126+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright 2010-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.codegen.poet.model;
17+
18+
import com.squareup.javapoet.ClassName;
19+
import com.squareup.javapoet.MethodSpec;
20+
21+
import java.util.Arrays;
22+
import java.util.List;
23+
import javax.lang.model.element.Modifier;
24+
25+
import software.amazon.awssdk.awscore.exception.AwsErrorDetails;
26+
27+
public class ExceptionProperties {
28+
29+
private ExceptionProperties() {}
30+
31+
public static List<MethodSpec> builderInterfaceMethods(ClassName className) {
32+
return Arrays.asList(
33+
builderMethod(className, "awsErrorDetails", AwsErrorDetails.class),
34+
builderMethod(className, "message", String.class),
35+
builderMethod(className, "requestId", String.class),
36+
builderMethod(className, "statusCode", int.class),
37+
builderMethod(className, "cause", Throwable.class));
38+
}
39+
40+
public static List<MethodSpec> builderImplMethods(ClassName className) {
41+
return Arrays.asList(
42+
builderImplMethods(className, "awsErrorDetails", AwsErrorDetails.class),
43+
builderImplMethods(className, "message", String.class),
44+
builderImplMethods(className, "requestId", String.class),
45+
builderImplMethods(className, "statusCode", int.class),
46+
builderImplMethods(className, "cause", Throwable.class));
47+
}
48+
49+
private static MethodSpec builderMethod(ClassName className, String name, Class clazz) {
50+
return MethodSpec.methodBuilder(name)
51+
.addAnnotation(Override.class)
52+
.returns(className)
53+
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
54+
.addParameter(clazz, name)
55+
.build();
56+
}
57+
58+
private static MethodSpec builderImplMethods(ClassName className, String name, Class clazz) {
59+
return MethodSpec.methodBuilder(name)
60+
.addAnnotation(Override.class)
61+
.returns(className)
62+
.addModifiers(Modifier.PUBLIC)
63+
.addParameter(clazz, name)
64+
.addStatement("this." + name + " = " + name)
65+
.addStatement("return this")
66+
.build();
67+
}
68+
}

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

Lines changed: 18 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ class ModelBuilderSpecs {
4747

4848
ModelBuilderSpecs(IntermediateModel intermediateModel,
4949
ShapeModel shapeModel,
50-
ShapeModelSpec shapeModelSpec,
5150
TypeProvider typeProvider) {
5251
this.intermediateModel = intermediateModel;
5352
this.shapeModel = shapeModel;
@@ -76,10 +75,8 @@ public TypeSpec builderInterface() {
7675
});
7776

7877
if (isException()) {
79-
builder.addMethod(MethodSpec.methodBuilder("message")
80-
.returns(builderInterfaceName())
81-
.addParameter(String.class, "message")
82-
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT).build());
78+
builder.addSuperinterface(parentExceptionBuilder().nestedClass("Builder"));
79+
builder.addMethods(ExceptionProperties.builderInterfaceMethods(builderInterfaceName()));
8380
}
8481

8582
if (isRequest()) {
@@ -102,13 +99,27 @@ public TypeSpec builderInterface() {
10299
return builder.build();
103100
}
104101

102+
private ClassName parentExceptionBuilder() {
103+
final String customExceptionBase = intermediateModel.getCustomizationConfig()
104+
.getSdkModeledExceptionBaseClassName();
105+
if (customExceptionBase != null) {
106+
return poetExtensions.getModelClass(customExceptionBase);
107+
}
108+
return poetExtensions.getModelClass(intermediateModel.getSdkModeledExceptionBaseClassName());
109+
}
110+
105111
public TypeSpec beanStyleBuilder() {
106112
TypeSpec.Builder builderClassBuilder = TypeSpec.classBuilder(builderImplName())
107113
.addSuperinterface(builderInterfaceName())
108114
// TODO: Uncomment this once property shadowing is fixed
109115
//.addSuperinterface(copyableBuilderSuperInterface())
110116
.superclass(builderImplSuperClass())
111117
.addModifiers(Modifier.STATIC, Modifier.FINAL);
118+
119+
if (isException()) {
120+
builderClassBuilder.superclass(parentExceptionBuilder().nestedClass("BuilderImpl"));
121+
}
122+
112123
builderClassBuilder.addFields(fields());
113124
builderClassBuilder.addMethod(noargConstructor());
114125
builderClassBuilder.addMethod(modelCopyConstructor());
@@ -146,12 +157,6 @@ private List<FieldSpec> fields() {
146157
return fieldSpec;
147158
}).collect(Collectors.toList());
148159

149-
// Inject a message member for the isException message
150-
if (isException()) {
151-
fields = new ArrayList<>(fields);
152-
fields.add(FieldSpec.builder(String.class, "message", Modifier.PRIVATE).build());
153-
}
154-
155160
return fields;
156161
}
157162

@@ -166,7 +171,7 @@ private MethodSpec modelCopyConstructor() {
166171
.addModifiers(Modifier.PRIVATE)
167172
.addParameter(classToBuild(), "model");
168173

169-
if (isRequest() || isResponse()) {
174+
if (isRequest() || isResponse() || isException()) {
170175
copyBuilderCtor.addCode("super(model);");
171176
}
172177

@@ -175,10 +180,6 @@ private MethodSpec modelCopyConstructor() {
175180
copyBuilderCtor.addStatement("$N(model.$N)", m.getFluentSetterMethodName(), name);
176181
});
177182

178-
if (isException()) {
179-
copyBuilderCtor.addStatement("this.message = model.getMessage()");
180-
}
181-
182183
return copyBuilderCtor.build();
183184
}
184185

@@ -193,8 +194,7 @@ private List<MethodSpec> accessors() {
193194
});
194195

195196
if (isException()) {
196-
accessors.addAll(exceptionMessageGetters());
197-
accessors.addAll(exceptionMessageSetters());
197+
accessors.addAll(ExceptionProperties.builderImplMethods(builderImplName()));
198198
}
199199

200200
if (isRequest()) {
@@ -258,45 +258,4 @@ private List<TypeName> builderSuperInterfaces() {
258258
classToBuild().nestedClass("Builder"), classToBuild()));
259259
return superInterfaces;
260260
}
261-
262-
private List<MethodSpec> exceptionMessageGetters() {
263-
List<MethodSpec> getters = new ArrayList<>();
264-
265-
// bean style
266-
getters.add(MethodSpec.methodBuilder("getMessage")
267-
.addModifiers(Modifier.PUBLIC)
268-
.returns(String.class)
269-
.addStatement("return message")
270-
.build());
271-
272-
getters.add(MethodSpec.methodBuilder("message")
273-
.addModifiers(Modifier.PUBLIC)
274-
.returns(String.class)
275-
.addStatement("return message")
276-
.build());
277-
278-
return getters;
279-
}
280-
281-
private List<MethodSpec> exceptionMessageSetters() {
282-
List<MethodSpec> setters = new ArrayList<>();
283-
284-
// bean style
285-
setters.add(MethodSpec.methodBuilder("setMessage")
286-
.addModifiers(Modifier.PUBLIC)
287-
.addParameter(String.class, "message")
288-
.addStatement("this.message = message")
289-
.build());
290-
291-
setters.add(MethodSpec.methodBuilder("message")
292-
.addModifiers(Modifier.PUBLIC)
293-
.returns(builderInterfaceName())
294-
.addAnnotation(Override.class)
295-
.addParameter(String.class, "message")
296-
.addStatement("this.message = message")
297-
.addStatement("return this")
298-
.build());
299-
300-
return setters;
301-
}
302261
}

0 commit comments

Comments
 (0)