Migrate ProjectDescription to an interface

This commit migrates ProjectDescription to an interface with read-only
accessors and create a MutableProjectDescription implementation that can
be used for both purposes.

As a result, the type separation between ResolvedProjectDescription and
ProjectDescription is no longer necessary.

Closes gh-993
This commit is contained in:
Stephane Nicoll
2019-08-23 18:47:26 +02:00
parent 67de21f629
commit 286e38888c
70 changed files with 565 additions and 592 deletions

View File

@@ -26,7 +26,7 @@ import java.util.function.Supplier;
import io.spring.initializr.generator.io.IndentingWriterFactory;
import io.spring.initializr.generator.io.SimpleIndentStrategy;
import io.spring.initializr.generator.project.ProjectDescription;
import io.spring.initializr.generator.project.MutableProjectDescription;
import io.spring.initializr.generator.project.ProjectDirectoryFactory;
import io.spring.initializr.generator.project.ProjectGenerationContext;
import io.spring.initializr.generator.project.ProjectGenerationException;
@@ -43,21 +43,23 @@ public abstract class AbstractProjectGenerationTester<SELF extends AbstractProje
private final Consumer<ProjectGenerationContext> contextInitializer;
private final Consumer<ProjectDescription> descriptionCustomizer;
private final Consumer<MutableProjectDescription> descriptionCustomizer;
protected AbstractProjectGenerationTester(Map<Class<?>, Supplier<?>> beanDefinitions) {
this(beanDefinitions, defaultContextInitializer(), defaultDescriptionCustomizer());
}
protected AbstractProjectGenerationTester(Map<Class<?>, Supplier<?>> beanDefinitions,
Consumer<ProjectGenerationContext> contextInitializer, Consumer<ProjectDescription> descriptionCustomizer) {
Consumer<ProjectGenerationContext> contextInitializer,
Consumer<MutableProjectDescription> descriptionCustomizer) {
this.beanDefinitions = new LinkedHashMap<>(beanDefinitions);
this.descriptionCustomizer = descriptionCustomizer;
this.contextInitializer = contextInitializer;
}
protected abstract SELF newInstance(Map<Class<?>, Supplier<?>> beanDefinitions,
Consumer<ProjectGenerationContext> contextInitializer, Consumer<ProjectDescription> descriptionCustomizer);
Consumer<ProjectGenerationContext> contextInitializer,
Consumer<MutableProjectDescription> descriptionCustomizer);
public <T> SELF withBean(Class<T> beanType, Supplier<T> beanDefinition) {
LinkedHashMap<Class<?>, Supplier<?>> beans = new LinkedHashMap<>(this.beanDefinitions);
@@ -79,7 +81,7 @@ public abstract class AbstractProjectGenerationTester<SELF extends AbstractProje
return newInstance(this.beanDefinitions, this.contextInitializer.andThen(context), this.descriptionCustomizer);
}
public SELF withDescriptionCustomizer(Consumer<ProjectDescription> description) {
public SELF withDescriptionCustomizer(Consumer<MutableProjectDescription> description) {
return newInstance(this.beanDefinitions, this.contextInitializer,
this.descriptionCustomizer.andThen(description));
}
@@ -89,7 +91,7 @@ public abstract class AbstractProjectGenerationTester<SELF extends AbstractProje
};
}
protected static Consumer<ProjectDescription> defaultDescriptionCustomizer() {
protected static Consumer<MutableProjectDescription> defaultDescriptionCustomizer() {
return (projectDescription) -> {
if (projectDescription.getGroupId() == null) {
projectDescription.setGroupId("com.example");
@@ -106,7 +108,8 @@ public abstract class AbstractProjectGenerationTester<SELF extends AbstractProje
};
}
protected <T> T invokeProjectGeneration(ProjectDescription description, ProjectGenerationInvoker<T> invoker) {
protected <T> T invokeProjectGeneration(MutableProjectDescription description,
ProjectGenerationInvoker<T> invoker) {
this.descriptionCustomizer.accept(description);
try {
return invoker.generate(beansConfigurer().andThen(this.contextInitializer));

View File

@@ -24,11 +24,11 @@ import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import io.spring.initializr.generator.project.MutableProjectDescription;
import io.spring.initializr.generator.project.ProjectAssetGenerator;
import io.spring.initializr.generator.project.ProjectDescription;
import io.spring.initializr.generator.project.ProjectDirectoryFactory;
import io.spring.initializr.generator.project.ProjectGenerationContext;
import io.spring.initializr.generator.project.ResolvedProjectDescription;
import io.spring.initializr.generator.project.contributor.ProjectContributor;
/**
@@ -47,13 +47,15 @@ public class ProjectAssetTester extends AbstractProjectGenerationTester<ProjectA
}
private ProjectAssetTester(Map<Class<?>, Supplier<?>> beanDefinitions,
Consumer<ProjectGenerationContext> contextInitializer, Consumer<ProjectDescription> descriptionCustomizer) {
Consumer<ProjectGenerationContext> contextInitializer,
Consumer<MutableProjectDescription> descriptionCustomizer) {
super(beanDefinitions, contextInitializer, descriptionCustomizer);
}
@Override
protected ProjectAssetTester newInstance(Map<Class<?>, Supplier<?>> beanDefinitions,
Consumer<ProjectGenerationContext> contextInitializer, Consumer<ProjectDescription> descriptionCustomizer) {
Consumer<ProjectGenerationContext> contextInitializer,
Consumer<MutableProjectDescription> descriptionCustomizer) {
return new ProjectAssetTester(beanDefinitions, contextInitializer, descriptionCustomizer);
}
@@ -69,11 +71,10 @@ public class ProjectAssetTester extends AbstractProjectGenerationTester<ProjectA
* @return the project asset
* @see #withConfiguration(Class[])
*/
public <T> T generate(ProjectDescription description, ProjectAssetGenerator<T> projectAssetGenerator) {
public <T> T generate(MutableProjectDescription description, ProjectAssetGenerator<T> projectAssetGenerator) {
return invokeProjectGeneration(description, (contextInitializer) -> {
try (ProjectGenerationContext context = new ProjectGenerationContext()) {
ResolvedProjectDescription resolvedProjectDescription = new ResolvedProjectDescription(description);
context.registerBean(ResolvedProjectDescription.class, () -> resolvedProjectDescription);
context.registerBean(ProjectDescription.class, () -> description);
contextInitializer.accept(context);
context.refresh();
return projectAssetGenerator.generate(context);
@@ -88,14 +89,14 @@ public class ProjectAssetTester extends AbstractProjectGenerationTester<ProjectA
* @return the {@link ProjectStructure} of the generated project
* @see #withConfiguration(Class[])
*/
public ProjectStructure generate(ProjectDescription description) {
public ProjectStructure generate(MutableProjectDescription description) {
return generate(description, runAllAvailableContributors());
}
private ProjectAssetGenerator<ProjectStructure> runAllAvailableContributors() {
return (context) -> {
Path projectDirectory = context.getBean(ProjectDirectoryFactory.class)
.createProjectDirectory(context.getBean(ResolvedProjectDescription.class));
.createProjectDirectory(context.getBean(ProjectDescription.class));
List<ProjectContributor> projectContributors = context.getBeanProvider(ProjectContributor.class)
.orderedStream().collect(Collectors.toList());
for (ProjectContributor projectContributor : projectContributors) {

View File

@@ -26,8 +26,8 @@ import io.spring.initializr.generator.io.IndentingWriterFactory;
import io.spring.initializr.generator.io.SimpleIndentStrategy;
import io.spring.initializr.generator.io.template.MustacheTemplateRenderer;
import io.spring.initializr.generator.project.DefaultProjectAssetGenerator;
import io.spring.initializr.generator.project.MutableProjectDescription;
import io.spring.initializr.generator.project.ProjectAssetGenerator;
import io.spring.initializr.generator.project.ProjectDescription;
import io.spring.initializr.generator.project.ProjectGenerationContext;
import io.spring.initializr.generator.project.ProjectGenerator;
@@ -39,7 +39,8 @@ import io.spring.initializr.generator.project.ProjectGenerator;
public class ProjectGeneratorTester extends AbstractProjectGenerationTester<ProjectGeneratorTester> {
private ProjectGeneratorTester(Map<Class<?>, Supplier<?>> beanDefinitions,
Consumer<ProjectGenerationContext> contextInitializer, Consumer<ProjectDescription> descriptionCustomizer) {
Consumer<ProjectGenerationContext> contextInitializer,
Consumer<MutableProjectDescription> descriptionCustomizer) {
super(beanDefinitions, contextInitializer, descriptionCustomizer);
}
@@ -56,11 +57,12 @@ public class ProjectGeneratorTester extends AbstractProjectGenerationTester<Proj
@Override
protected ProjectGeneratorTester newInstance(Map<Class<?>, Supplier<?>> beanDefinitions,
Consumer<ProjectGenerationContext> contextInitializer, Consumer<ProjectDescription> descriptionCustomizer) {
Consumer<ProjectGenerationContext> contextInitializer,
Consumer<MutableProjectDescription> descriptionCustomizer) {
return new ProjectGeneratorTester(beanDefinitions, contextInitializer, descriptionCustomizer);
}
public ProjectStructure generate(ProjectDescription description) {
public ProjectStructure generate(MutableProjectDescription description) {
return invokeProjectGeneration(description, (contextInitializer) -> {
Path directory = new ProjectGenerator(contextInitializer).generate(description,
new DefaultProjectAssetGenerator());
@@ -68,7 +70,7 @@ public class ProjectGeneratorTester extends AbstractProjectGenerationTester<Proj
});
}
public <T> T generate(ProjectDescription description, ProjectAssetGenerator<T> projectAssetGenerator) {
public <T> T generate(MutableProjectDescription description, ProjectAssetGenerator<T> projectAssetGenerator) {
return invokeProjectGeneration(description, (contextInitializer) -> new ProjectGenerator(contextInitializer)
.generate(description, projectAssetGenerator));
}

View File

@@ -21,10 +21,10 @@ import java.nio.file.Path;
import java.util.function.Consumer;
import io.spring.initializr.generator.buildsystem.maven.MavenBuildSystem;
import io.spring.initializr.generator.project.MutableProjectDescription;
import io.spring.initializr.generator.project.ProjectDescription;
import io.spring.initializr.generator.project.ProjectDescriptionCustomizer;
import io.spring.initializr.generator.project.ProjectGenerator;
import io.spring.initializr.generator.project.ResolvedProjectDescription;
import io.spring.initializr.generator.project.contributor.ProjectContributor;
import io.spring.initializr.generator.version.Version;
import org.junit.jupiter.api.Test;
@@ -48,14 +48,14 @@ class ProjectGeneratorTests {
@Test
void generateInvokedProcessor() {
ProjectDescription description = new ProjectDescription();
MutableProjectDescription description = new MutableProjectDescription();
description.setBuildSystem(new MavenBuildSystem());
Version platformVersion = Version.parse("2.1.0.RELEASE");
description.setPackageName("com.example.test");
ResolvedProjectDescription resolvedProjectDescription = this.projectTester.generate(description,
(projectGenerationContext) -> projectGenerationContext.getBean(ResolvedProjectDescription.class));
assertThat(resolvedProjectDescription.getPlatformVersion()).isEqualTo(platformVersion);
assertThat(resolvedProjectDescription.getPackageName()).isEqualTo("com.example.test");
ProjectDescription ProjectDescription = this.projectTester.generate(description,
(projectGenerationContext) -> projectGenerationContext.getBean(ProjectDescription.class));
assertThat(ProjectDescription.getPlatformVersion()).isEqualTo(platformVersion);
assertThat(ProjectDescription.getPackageName()).isEqualTo("com.example.test");
}
@Test
@@ -69,14 +69,14 @@ class ProjectGeneratorTests {
description.setGroupId("com.acme");
}));
});
ProjectDescription description = new ProjectDescription();
MutableProjectDescription description = new MutableProjectDescription();
description.setGroupId("com.example.demo");
description.setName("Original");
ResolvedProjectDescription resolvedProjectDescription = tester.generate(description,
(projectGenerationContext) -> projectGenerationContext.getBean(ResolvedProjectDescription.class));
assertThat(resolvedProjectDescription.getGroupId()).isEqualTo("com.acme");
assertThat(resolvedProjectDescription.getName()).isEqualTo("Test");
ProjectDescription ProjectDescription = tester.generate(description,
(projectGenerationContext) -> projectGenerationContext.getBean(ProjectDescription.class));
assertThat(ProjectDescription.getGroupId()).isEqualTo("com.acme");
assertThat(ProjectDescription.getName()).isEqualTo("Test");
}
@Test
@@ -91,7 +91,7 @@ class ProjectGeneratorTests {
Files.createFile(subDir.resolve("Test.src"));
});
});
ProjectStructure project = tester.generate(new ProjectDescription());
ProjectStructure project = tester.generate(new MutableProjectDescription());
assertThat(project).filePaths().containsOnly("test.text", "src/main/test/Test.src");
}
@@ -99,15 +99,15 @@ class ProjectGeneratorTests {
private final Integer order;
private final Consumer<ProjectDescription> projectDescription;
private final Consumer<MutableProjectDescription> projectDescription;
TestProjectDescriptionCustomizer(Integer order, Consumer<ProjectDescription> projectDescription) {
TestProjectDescriptionCustomizer(Integer order, Consumer<MutableProjectDescription> projectDescription) {
this.order = order;
this.projectDescription = projectDescription;
}
@Override
public void customize(ProjectDescription description) {
public void customize(MutableProjectDescription description) {
this.projectDescription.accept(description);
}