Skip to content

Commit f981caa

Browse files
authored
Update generator plugin to support validators (#6142)
This commit updates the generation mojo to suppport validators: - Add flag for controling whether the validation report is written to disk - Build all models to IntermediateModel upfront - If a service model targets another for sharing shapes, also pass in the target service IntermedidateModel
1 parent be78c0c commit f981caa

File tree

3 files changed

+94
-15
lines changed

3 files changed

+94
-15
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"type": "feature",
3+
"category": "Code Generator Maven Plugin",
4+
"contributor": "",
5+
"description": "Update the generator plugin to support model validation during code generation. In addition, this adds the `writeValidationReport` flag to support writing the validation report to disk."
6+
}

codegen-maven-plugin/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@
5757
<groupId>software.amazon.awssdk</groupId>
5858
<version>${awsjavasdk.version}</version>
5959
</dependency>
60+
<dependency>
61+
<artifactId>utils</artifactId>
62+
<groupId>software.amazon.awssdk</groupId>
63+
<version>${awsjavasdk.version}</version>
64+
</dependency>
6065
<dependency>
6166
<groupId>org.junit.jupiter</groupId>
6267
<artifactId>junit-jupiter</artifactId>

codegen-maven-plugin/src/main/java/software/amazon/awssdk/codegen/maven/plugin/GenerationMojo.java

Lines changed: 83 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@
2121
import java.nio.file.Path;
2222
import java.nio.file.Paths;
2323
import java.nio.file.attribute.BasicFileAttributes;
24+
import java.util.HashMap;
25+
import java.util.List;
26+
import java.util.Map;
2427
import java.util.Optional;
28+
import java.util.stream.Collectors;
2529
import java.util.stream.Stream;
2630
import org.apache.maven.plugin.AbstractMojo;
2731
import org.apache.maven.plugin.MojoExecutionException;
@@ -30,21 +34,23 @@
3034
import org.apache.maven.project.MavenProject;
3135
import software.amazon.awssdk.codegen.C2jModels;
3236
import software.amazon.awssdk.codegen.CodeGenerator;
37+
import software.amazon.awssdk.codegen.IntermediateModelBuilder;
3338
import software.amazon.awssdk.codegen.internal.Utils;
3439
import software.amazon.awssdk.codegen.model.config.customization.CustomizationConfig;
40+
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
3541
import software.amazon.awssdk.codegen.model.rules.endpoints.EndpointTestSuiteModel;
3642
import software.amazon.awssdk.codegen.model.service.EndpointRuleSetModel;
3743
import software.amazon.awssdk.codegen.model.service.Paginators;
3844
import software.amazon.awssdk.codegen.model.service.ServiceModel;
3945
import software.amazon.awssdk.codegen.model.service.Waiters;
4046
import software.amazon.awssdk.codegen.utils.ModelLoaderUtils;
47+
import software.amazon.awssdk.utils.StringUtils;
4148

4249
/**
4350
* The Maven mojo to generate Java client code using software.amazon.awssdk:codegen module.
4451
*/
4552
@Mojo(name = "generate")
4653
public class GenerationMojo extends AbstractMojo {
47-
4854
private static final String MODEL_FILE = "service-2.json";
4955
private static final String CUSTOMIZATION_CONFIG_FILE = "customization.config";
5056
private static final String WAITERS_FILE = "waiters-2.json";
@@ -62,6 +68,8 @@ public class GenerationMojo extends AbstractMojo {
6268
@Parameter(property = "writeIntermediateModel", defaultValue = "false")
6369
private boolean writeIntermediateModel;
6470

71+
@Parameter(property = "writeValidationReport", defaultValue = "false")
72+
private boolean writeValidationReport;
6573

6674
@Parameter(defaultValue = "${project}", readonly = true)
6775
private MavenProject project;
@@ -76,22 +84,59 @@ public void execute() throws MojoExecutionException {
7684
this.resourcesDirectory = Paths.get(outputDirectory).resolve("generated-resources").resolve("sdk-resources");
7785
this.testsDirectory = Paths.get(outputDirectory).resolve("generated-test-sources").resolve("sdk-tests");
7886

79-
findModelRoots().forEach(p -> {
80-
Path modelRootPath = p.modelRoot;
81-
getLog().info("Loading from: " + modelRootPath.toString());
82-
generateCode(C2jModels.builder()
83-
.customizationConfig(p.customizationConfig)
84-
.serviceModel(loadServiceModel(modelRootPath))
85-
.waitersModel(loadWaiterModel(modelRootPath))
86-
.paginatorsModel(loadPaginatorModel(modelRootPath))
87-
.endpointRuleSetModel(loadEndpointRuleSetModel(modelRootPath))
88-
.endpointTestSuiteModel(loadEndpointTestSuiteModel(modelRootPath))
89-
.build());
87+
List<GenerationParams> generationParams = initGenerationParams();
88+
89+
Map<String, IntermediateModel> serviceNameToModelMap = new HashMap<>();
90+
91+
generationParams.forEach(
92+
params -> {
93+
IntermediateModel model = params.intermediateModel;
94+
String lowercaseServiceName = StringUtils.lowerCase(model.getMetadata().getServiceName());
95+
IntermediateModel previous = serviceNameToModelMap.put(lowercaseServiceName, model);
96+
if (previous != null) {
97+
String warning = String.format("Multiple service models found with service name %s. Model validation "
98+
+ "will likely be incorrect", lowercaseServiceName);
99+
getLog().warn(warning);
100+
}
101+
});
102+
103+
// Update each param with the intermediate model it shares models with, if any
104+
generationParams.forEach(params -> {
105+
CustomizationConfig customizationConfig = params.intermediateModel.getCustomizationConfig();
106+
107+
if (customizationConfig.getShareModelConfig() != null) {
108+
String shareModelWithName = customizationConfig.getShareModelConfig().getShareModelWith();
109+
params.withShareModelsTarget(serviceNameToModelMap.get(shareModelWithName));
110+
}
90111
});
112+
113+
generationParams.forEach(this::generateCode);
114+
91115
project.addCompileSourceRoot(sourcesDirectory.toFile().getAbsolutePath());
92116
project.addTestCompileSourceRoot(testsDirectory.toFile().getAbsolutePath());
93117
}
94118

119+
private List<GenerationParams> initGenerationParams() throws MojoExecutionException {
120+
List<ModelRoot> modelRoots = findModelRoots().collect(Collectors.toList());
121+
122+
return modelRoots.stream().map(r -> {
123+
Path modelRootPath = r.modelRoot;
124+
getLog().info("Loading from: " + modelRootPath.toString());
125+
C2jModels c2jModels = C2jModels.builder()
126+
.customizationConfig(r.customizationConfig)
127+
.serviceModel(loadServiceModel(modelRootPath))
128+
.waitersModel(loadWaiterModel(modelRootPath))
129+
.paginatorsModel(loadPaginatorModel(modelRootPath))
130+
.endpointRuleSetModel(loadEndpointRuleSetModel(modelRootPath))
131+
.endpointTestSuiteModel(loadEndpointTestSuiteModel(modelRootPath))
132+
.build();
133+
String intermediateModelFileNamePrefix = intermediateModelFileNamePrefix(c2jModels);
134+
IntermediateModel intermediateModel = new IntermediateModelBuilder(c2jModels).build();
135+
return new GenerationParams().withIntermediateModel(intermediateModel)
136+
.withIntermediateModelFileNamePrefix(intermediateModelFileNamePrefix);
137+
}).collect(Collectors.toList());
138+
}
139+
95140
private Stream<ModelRoot> findModelRoots() throws MojoExecutionException {
96141
try {
97142
return Files.find(codeGenResources.toPath(), 10, this::isModelFile)
@@ -111,13 +156,15 @@ private boolean isModelFile(Path p, BasicFileAttributes a) {
111156
return p.toString().endsWith(MODEL_FILE);
112157
}
113158

114-
private void generateCode(C2jModels models) {
159+
private void generateCode(GenerationParams params) {
115160
CodeGenerator.builder()
116-
.models(models)
161+
.intermediateModel(params.intermediateModel)
162+
.shareModelsTarget(params.shareModelsTarget)
117163
.sourcesDirectory(sourcesDirectory.toFile().getAbsolutePath())
118164
.resourcesDirectory(resourcesDirectory.toFile().getAbsolutePath())
119165
.testsDirectory(testsDirectory.toFile().getAbsolutePath())
120-
.intermediateModelFileNamePrefix(intermediateModelFileNamePrefix(models))
166+
.intermediateModelFileNamePrefix(params.intermediateModelFileNamePrefix)
167+
.emitValidationReport(writeValidationReport)
121168
.build()
122169
.execute();
123170
}
@@ -178,4 +225,25 @@ private ModelRoot(Path modelRoot, CustomizationConfig customizationConfig) {
178225
this.customizationConfig = customizationConfig;
179226
}
180227
}
228+
229+
private static class GenerationParams {
230+
private IntermediateModel intermediateModel;
231+
private IntermediateModel shareModelsTarget;
232+
private String intermediateModelFileNamePrefix;
233+
234+
public GenerationParams withIntermediateModel(IntermediateModel intermediateModel) {
235+
this.intermediateModel = intermediateModel;
236+
return this;
237+
}
238+
239+
public GenerationParams withShareModelsTarget(IntermediateModel shareModelsTarget) {
240+
this.shareModelsTarget = shareModelsTarget;
241+
return this;
242+
}
243+
244+
public GenerationParams withIntermediateModelFileNamePrefix(String intermediateModelFileNamePrefix) {
245+
this.intermediateModelFileNamePrefix = intermediateModelFileNamePrefix;
246+
return this;
247+
}
248+
}
181249
}

0 commit comments

Comments
 (0)