diff --git a/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/code/kotlin/KotlinJpaMavenBuildCustomizer.java b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/code/kotlin/KotlinJpaMavenBuildCustomizer.java index 7088056d..b6755002 100644 --- a/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/code/kotlin/KotlinJpaMavenBuildCustomizer.java +++ b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/code/kotlin/KotlinJpaMavenBuildCustomizer.java @@ -41,9 +41,9 @@ public class KotlinJpaMavenBuildCustomizer implements BuildCustomizer configuration.add("compilerPlugins", - (compilerPlugins) -> compilerPlugins.add("plugin", "jpa"))); + kotlinNoArgPlugin.configuration((configuration) -> configuration.parameter( + "compilerPlugins", + (compilerPlugins) -> compilerPlugins.parameter("plugin", "jpa"))); } } diff --git a/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/code/kotlin/KotlinMavenBuildCustomizer.java b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/code/kotlin/KotlinMavenBuildCustomizer.java index 8c3e5cfd..39c47192 100644 --- a/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/code/kotlin/KotlinMavenBuildCustomizer.java +++ b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/code/kotlin/KotlinMavenBuildCustomizer.java @@ -45,10 +45,10 @@ class KotlinMavenBuildCustomizer implements BuildCustomizer { MavenPlugin kotlinMavenPlugin = build.plugin("org.jetbrains.kotlin", "kotlin-maven-plugin"); kotlinMavenPlugin.configuration((configuration) -> { - configuration.add("args", (args) -> this.settings.getCompilerArgs() - .forEach((arg) -> args.add("arg", arg))); - configuration.add("compilerPlugins", - (compilerPlugins) -> compilerPlugins.add("plugin", "spring")); + configuration.parameter("args", (args) -> this.settings.getCompilerArgs() + .forEach((arg) -> args.parameter("arg", arg))); + configuration.parameter("compilerPlugins", + (compilerPlugins) -> compilerPlugins.parameter("plugin", "spring")); }); kotlinMavenPlugin.dependency("org.jetbrains.kotlin", "kotlin-maven-allopen", "${kotlin.version}"); diff --git a/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/code/kotlin/KotlinMavenFullBuildCustomizer.java b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/code/kotlin/KotlinMavenFullBuildCustomizer.java index 067096e1..800929dc 100644 --- a/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/code/kotlin/KotlinMavenFullBuildCustomizer.java +++ b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/code/kotlin/KotlinMavenFullBuildCustomizer.java @@ -42,11 +42,11 @@ class KotlinMavenFullBuildCustomizer implements BuildCustomizer { MavenPlugin kotlinMavenPlugin = build.plugin("org.jetbrains.kotlin", "kotlin-maven-plugin", "${kotlin.version}"); kotlinMavenPlugin.configuration((configuration) -> { - configuration.add("args", (args) -> this.settings.getCompilerArgs() - .forEach((arg) -> args.add("arg", arg))); - configuration.add("compilerPlugins", - (compilerPlugins) -> compilerPlugins.add("plugin", "spring")); - configuration.add("jvmTarget", this.settings.getJvmTarget()); + configuration.parameter("args", (args) -> this.settings.getCompilerArgs() + .forEach((arg) -> args.parameter("arg", arg))); + configuration.parameter("compilerPlugins", + (compilerPlugins) -> compilerPlugins.parameter("plugin", "spring")); + configuration.parameter("jvmTarget", this.settings.getJvmTarget()); }); kotlinMavenPlugin.execution("compile", (compile) -> compile.phase("compile").goal("compile")); diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/maven/MavenPlugin.java b/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/maven/MavenPlugin.java index 68ff6f26..1c2877f4 100644 --- a/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/maven/MavenPlugin.java +++ b/initializr-generator/src/main/java/io/spring/initializr/generator/buildsystem/maven/MavenPlugin.java @@ -18,8 +18,11 @@ package io.spring.initializr.generator.buildsystem.maven; import java.util.ArrayList; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.function.Consumer; +import java.util.stream.Collectors; /** * A plugin in a {@link MavenBuild}. @@ -139,23 +142,58 @@ public class MavenPlugin { */ public static class ConfigurationCustomization { - private final List settings = new ArrayList<>(); + private final Map settings = new LinkedHashMap<>(); - public ConfigurationCustomization add(String key, String value) { - this.settings.add(new Setting(key, value)); + /** + * Set the specified parameter with a single value. + * @param name the name of the parameter + * @param value the single value of the parameter + * @return this for method chaining + */ + public ConfigurationCustomization parameter(String name, String value) { + this.settings.put(name, value); return this; } - public ConfigurationCustomization add(String key, + /** + * Configure the parameter with the specified {@code name}. + * @param parameter the name of the parameter + * @param consumer a consumer to further configure the parameter + * @return this for method chaining + * @throws IllegalArgumentException if a parameter with the same name is + * registered with a single value + */ + public ConfigurationCustomization parameter(String parameter, Consumer consumer) { - ConfigurationCustomization nestedConfiguration = new ConfigurationCustomization(); + Object value = this.settings.computeIfAbsent(parameter, + (id) -> new ConfigurationCustomization()); + if (!(value instanceof ConfigurationCustomization)) { + throw new IllegalArgumentException(String.format( + "Could not customize parameter '%s', a single value %s is already registered", + parameter, value)); + } + ConfigurationCustomization nestedConfiguration = (ConfigurationCustomization) value; consumer.accept(nestedConfiguration); - this.settings.add(new Setting(key, nestedConfiguration.settings)); return this; } Configuration build() { - return new Configuration(this.settings); + return new Configuration(this.settings.entrySet().stream() + .map((entry) -> resolve(entry.getKey(), entry.getValue())) + .collect(Collectors.toList())); + } + + private Setting resolve(String key, Object value) { + if (value instanceof ConfigurationCustomization) { + List values = ((ConfigurationCustomization) value).settings + .entrySet().stream() + .map((entry) -> resolve(entry.getKey(), entry.getValue())) + .collect(Collectors.toList()); + return new Setting(key, values); + } + else { + return new Setting(key, value); + } } } diff --git a/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/maven/MavenBuildWriterTests.java b/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/maven/MavenBuildWriterTests.java index 92fa84ab..6401cdcc 100644 --- a/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/maven/MavenBuildWriterTests.java +++ b/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/maven/MavenBuildWriterTests.java @@ -336,9 +336,10 @@ class MavenBuildWriterTests { build.setArtifact("demo"); MavenPlugin kotlin = build.plugin("org.jetbrains.kotlin", "kotlin-maven-plugin"); kotlin.configuration((configuration) -> { - configuration.add("args", (args) -> args.add("arg", "-Xjsr305=strict")); - configuration.add("compilerPlugins", - (compilerPlugins) -> compilerPlugins.add("plugin", "spring")); + configuration.parameter("args", + (args) -> args.parameter("arg", "-Xjsr305=strict")); + configuration.parameter("compilerPlugins", + (compilerPlugins) -> compilerPlugins.parameter("plugin", "spring")); }); generatePom(build, (pom) -> { NodeAssert plugin = pom.nodeAtPath("/project/build/plugins/plugin"); @@ -363,8 +364,8 @@ class MavenBuildWriterTests { execution.goal("process-asciidoc"); execution.phase("generateProject-resources"); execution.configuration((configuration) -> { - configuration.add("doctype", "book"); - configuration.add("backend", "html"); + configuration.parameter("doctype", "book"); + configuration.parameter("backend", "html"); }); }); generatePom(build, (pom) -> { diff --git a/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/maven/MavenPluginTests.java b/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/maven/MavenPluginTests.java new file mode 100644 index 00000000..18c30b4e --- /dev/null +++ b/initializr-generator/src/test/java/io/spring/initializr/generator/buildsystem/maven/MavenPluginTests.java @@ -0,0 +1,112 @@ +/* + * Copyright 2012-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.initializr.generator.buildsystem.maven; + +import java.util.List; + +import io.spring.initializr.generator.buildsystem.maven.MavenPlugin.Setting; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +/** + * Tests for {@link MavenPlugin}. + * + * @author Stephane Nicoll + */ +class MavenPluginTests { + + @Test + void configurationCanBeCustomized() { + MavenPlugin plugin = new MavenPlugin("com.example", "test-plugin"); + plugin.configuration((customizer) -> customizer.parameter("enabled", "false") + .parameter("skip", "true")); + plugin.configuration((customizer) -> customizer.parameter("another", "test")); + assertThat(plugin.getConfiguration().getSettings().stream().map(Setting::getName)) + .containsExactly("enabled", "skip", "another"); + assertThat( + plugin.getConfiguration().getSettings().stream().map(Setting::getValue)) + .containsExactly("false", "true", "test"); + } + + @Test + void configurationCanBeOverridden() { + MavenPlugin plugin = new MavenPlugin("com.example", "test-plugin"); + plugin.configuration((customizer) -> customizer.parameter("enabled", "true")); + plugin.configuration((customizer) -> customizer.parameter("enabled", "false")); + assertThat(plugin.getConfiguration().getSettings().stream().map(Setting::getName)) + .containsExactly("enabled"); + assertThat( + plugin.getConfiguration().getSettings().stream().map(Setting::getValue)) + .containsExactly("false"); + } + + @Test + @SuppressWarnings("unchecked") + void configurationWithNestedValuesCanBeCustomized() { + MavenPlugin plugin = new MavenPlugin("com.example", "test-plugin"); + plugin.configuration((customizer) -> customizer.parameter("items", + (items) -> items.parameter("one", "true"))); + plugin.configuration((customizer) -> customizer.parameter("items", + (items) -> items.parameter("two", "false"))); + assertThat(plugin.getConfiguration().getSettings()).hasSize(1); + Setting setting = plugin.getConfiguration().getSettings().get(0); + assertThat(setting.getName()).isEqualTo("items"); + assertThat(setting.getValue()).isInstanceOf(List.class); + List values = (List) setting.getValue(); + assertThat(values.stream().map(Setting::getName)).containsExactly("one", "two"); + assertThat(values.stream().map(Setting::getValue)).containsExactly("true", + "false"); + } + + @Test + @SuppressWarnings("unchecked") + void configurationWithSeveralLevelOfNestedValuesCanBeCustomized() { + MavenPlugin plugin = new MavenPlugin("com.example", "test-plugin"); + plugin.configuration((customizer) -> customizer.parameter("items", + (items) -> items.parameter("subItems", + (subItems) -> subItems.parameter("one", "true")))); + plugin.configuration((customizer) -> customizer.parameter("items", + (items) -> items.parameter("subItems", (subItems) -> subItems + .parameter("one", "false").parameter("two", "true")))); + assertThat(plugin.getConfiguration().getSettings()).hasSize(1); + Setting setting = plugin.getConfiguration().getSettings().get(0); + assertThat(setting.getName()).isEqualTo("items"); + assertThat(setting.getValue()).isInstanceOf(List.class); + List items = (List) setting.getValue(); + assertThat(items).hasSize(1); + Setting item = items.get(0); + assertThat(item.getName()).isEqualTo("subItems"); + assertThat(item.getValue()).isInstanceOf(List.class); + List subItems = (List) item.getValue(); + assertThat(subItems.stream().map(Setting::getName)).containsExactly("one", "two"); + assertThat(subItems.stream().map(Setting::getValue)).containsExactly("false", + "true"); + } + + @Test + void configurationCannotBeSwitchedToNestedValue() { + MavenPlugin plugin = new MavenPlugin("com.example", "test-plugin"); + plugin.configuration((customizer) -> customizer.parameter("test", "value")); + assertThatIllegalArgumentException() + .isThrownBy(() -> plugin.configuration((customizer) -> customizer + .parameter("test", (test) -> test.parameter("one", "true")))) + .withMessageContaining("test").withMessageContaining("value"); + } + +}