Extract AotGenerateMojo to its own structure
This commit stops AotGenerateMojo from being an extension of the regular run infrastructure and used the opportunity to extract a number of utility classes to run a Java process. As a result, not all features of running an application is supported and exposed options now are targeted against AOT. See gh-31682
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
* Copyright 2012-2022 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.
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
package org.springframework.boot.maven;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -25,6 +29,8 @@ import org.apache.maven.artifact.Artifact;
|
||||
import org.apache.maven.plugin.AbstractMojo;
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
import org.apache.maven.plugins.annotations.Parameter;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.apache.maven.shared.artifact.filter.collection.AbstractArtifactFeatureFilter;
|
||||
import org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException;
|
||||
import org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter;
|
||||
import org.apache.maven.shared.artifact.filter.collection.FilterArtifacts;
|
||||
@@ -38,6 +44,13 @@ import org.apache.maven.shared.artifact.filter.collection.FilterArtifacts;
|
||||
*/
|
||||
public abstract class AbstractDependencyFilterMojo extends AbstractMojo {
|
||||
|
||||
/**
|
||||
* The Maven project.
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@Parameter(defaultValue = "${project}", readonly = true, required = true)
|
||||
protected MavenProject project;
|
||||
|
||||
/**
|
||||
* Collection of artifact definitions to include. The {@link Include} element defines
|
||||
* mandatory {@code groupId} and {@code artifactId} properties and an optional
|
||||
@@ -76,6 +89,26 @@ public abstract class AbstractDependencyFilterMojo extends AbstractMojo {
|
||||
this.excludeGroupIds = excludeGroupIds;
|
||||
}
|
||||
|
||||
protected List<URL> getDependencyURLs(ArtifactsFilter... additionalFilters) throws MojoExecutionException {
|
||||
Set<Artifact> artifacts = filterDependencies(this.project.getArtifacts(), getFilters(additionalFilters));
|
||||
List<URL> urls = new ArrayList<>();
|
||||
for (Artifact artifact : artifacts) {
|
||||
if (artifact.getFile() != null) {
|
||||
urls.add(toURL(artifact.getFile()));
|
||||
}
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
|
||||
protected URL toURL(File file) {
|
||||
try {
|
||||
return file.toURI().toURL();
|
||||
}
|
||||
catch (MalformedURLException ex) {
|
||||
throw new IllegalStateException("Invalid URL for " + file, ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected final Set<Artifact> filterDependencies(Set<Artifact> dependencies, FilterArtifacts filters)
|
||||
throws MojoExecutionException {
|
||||
try {
|
||||
@@ -124,4 +157,17 @@ public abstract class AbstractDependencyFilterMojo extends AbstractMojo {
|
||||
return cleaned.toString();
|
||||
}
|
||||
|
||||
static class TestArtifactFilter extends AbstractArtifactFeatureFilter {
|
||||
|
||||
TestArtifactFilter() {
|
||||
super("", Artifact.SCOPE_TEST);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getArtifactFeature(Artifact artifact) {
|
||||
return artifact.getScope();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@@ -36,14 +37,18 @@ import javax.tools.JavaFileObject;
|
||||
import javax.tools.StandardJavaFileManager;
|
||||
import javax.tools.ToolProvider;
|
||||
|
||||
import org.apache.maven.execution.MavenSession;
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
import org.apache.maven.plugin.MojoFailureException;
|
||||
import org.apache.maven.plugins.annotations.Component;
|
||||
import org.apache.maven.plugins.annotations.LifecyclePhase;
|
||||
import org.apache.maven.plugins.annotations.Mojo;
|
||||
import org.apache.maven.plugins.annotations.Parameter;
|
||||
import org.apache.maven.plugins.annotations.ResolutionScope;
|
||||
import org.apache.maven.toolchain.ToolchainManager;
|
||||
|
||||
import org.springframework.boot.loader.tools.RunProcess;
|
||||
import org.springframework.boot.maven.CommandLineBuilder.ClasspathBuilder;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Invoke the AOT engine on the application.
|
||||
@@ -55,10 +60,35 @@ import org.springframework.boot.loader.tools.RunProcess;
|
||||
@Mojo(name = "aot-generate", defaultPhase = LifecyclePhase.PREPARE_PACKAGE, threadSafe = true,
|
||||
requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME,
|
||||
requiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME)
|
||||
public class AotGenerateMojo extends AbstractRunMojo {
|
||||
public class AotGenerateMojo extends AbstractDependencyFilterMojo {
|
||||
|
||||
private static final String AOT_PROCESSOR_CLASS_NAME = "org.springframework.boot.AotProcessor";
|
||||
|
||||
/**
|
||||
* The current Maven session. This is used for toolchain manager API calls.
|
||||
*/
|
||||
@Parameter(defaultValue = "${session}", readonly = true)
|
||||
private MavenSession session;
|
||||
|
||||
/**
|
||||
* The toolchain manager to use to locate a custom JDK.
|
||||
*/
|
||||
@Component
|
||||
private ToolchainManager toolchainManager;
|
||||
|
||||
/**
|
||||
* Directory containing the classes and resource files that should be packaged into
|
||||
* the archive.
|
||||
*/
|
||||
@Parameter(defaultValue = "${project.build.outputDirectory}", required = true)
|
||||
private File classesDirectory;
|
||||
|
||||
/**
|
||||
* Skip the execution.
|
||||
*/
|
||||
@Parameter(property = "spring-boot.aot.skip", defaultValue = "false")
|
||||
private boolean skip;
|
||||
|
||||
/**
|
||||
* Directory containing the generated sources.
|
||||
*/
|
||||
@@ -77,11 +107,40 @@ public class AotGenerateMojo extends AbstractRunMojo {
|
||||
@Parameter(defaultValue = "${project.build.directory}/spring-aot/main/classes", required = true)
|
||||
private File generatedClasses;
|
||||
|
||||
/**
|
||||
* List of JVM system properties to pass to the AOT process.
|
||||
*/
|
||||
@Parameter
|
||||
private Map<String, String> systemPropertyVariables;
|
||||
|
||||
/**
|
||||
* JVM arguments that should be associated with the AOT process. On command line, make
|
||||
* sure to wrap multiple values between quotes.
|
||||
*/
|
||||
@Parameter(property = "spring-boot.aot.jvmArguments")
|
||||
private String jvmArguments;
|
||||
|
||||
/**
|
||||
* Name of the main class to use as the source for the AOT process. If not specified
|
||||
* the first compiled class found that contains a 'main' method will be used.
|
||||
*/
|
||||
@Parameter(property = "spring-boot.aot.main-class")
|
||||
private String mainClass;
|
||||
|
||||
/**
|
||||
* Spring profiles to take into account for AOT processing.
|
||||
*/
|
||||
@Parameter
|
||||
private String[] profiles;
|
||||
|
||||
@Override
|
||||
protected void run(File workingDirectory, String startClassName, Map<String, String> environmentVariables)
|
||||
throws MojoExecutionException, MojoFailureException {
|
||||
public void execute() throws MojoExecutionException, MojoFailureException {
|
||||
if (this.skip) {
|
||||
getLog().debug("skipping execution as per configuration.");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
generateAotAssets(workingDirectory, startClassName, environmentVariables);
|
||||
generateAotAssets();
|
||||
compileSourceFiles();
|
||||
copyAll(this.generatedResources.toPath().resolve("META-INF/native-image"),
|
||||
this.classesDirectory.toPath().resolve("META-INF/native-image"));
|
||||
@@ -92,52 +151,39 @@ public class AotGenerateMojo extends AbstractRunMojo {
|
||||
}
|
||||
}
|
||||
|
||||
private void generateAotAssets(File workingDirectory, String startClassName,
|
||||
Map<String, String> environmentVariables) throws MojoExecutionException {
|
||||
List<String> args = new ArrayList<>();
|
||||
addJvmArgs(args);
|
||||
addClasspath(args);
|
||||
args.add(AOT_PROCESSOR_CLASS_NAME);
|
||||
// Adding arguments that are necessary for generation
|
||||
args.add(startClassName);
|
||||
args.add(this.generatedSources.toString());
|
||||
args.add(this.generatedResources.toString());
|
||||
args.add(this.generatedClasses.toString());
|
||||
args.add(this.project.getGroupId());
|
||||
args.add(this.project.getArtifactId());
|
||||
addArgs(args);
|
||||
private void generateAotAssets() throws MojoExecutionException {
|
||||
String applicationClass = (this.mainClass != null) ? this.mainClass
|
||||
: SpringBootApplicationClassFinder.findSingleClass(this.classesDirectory);
|
||||
List<String> aotArguments = new ArrayList<>();
|
||||
aotArguments.add(applicationClass);
|
||||
aotArguments.add(this.generatedSources.toString());
|
||||
aotArguments.add(this.generatedResources.toString());
|
||||
aotArguments.add(this.generatedClasses.toString());
|
||||
aotArguments.add(this.project.getGroupId());
|
||||
aotArguments.add(this.project.getArtifactId());
|
||||
if (!ObjectUtils.isEmpty(this.profiles)) {
|
||||
aotArguments.add("--spring.profiles.active=" + String.join(",", this.profiles));
|
||||
}
|
||||
// @formatter:off
|
||||
List<String> args = CommandLineBuilder.forMainClass(AOT_PROCESSOR_CLASS_NAME)
|
||||
.withSystemProperties(this.systemPropertyVariables)
|
||||
.withJvmArguments(new RunArguments(this.jvmArguments).asArray())
|
||||
.withClasspath(getClassPathUrls())
|
||||
.withArguments(aotArguments.toArray(String[]::new))
|
||||
.build();
|
||||
// @formatter:on
|
||||
if (getLog().isDebugEnabled()) {
|
||||
getLog().debug("Generating AOT assets using command: " + args);
|
||||
}
|
||||
int exitCode = forkJvm(workingDirectory, args, environmentVariables);
|
||||
if (!hasTerminatedSuccessfully(exitCode)) {
|
||||
throw new MojoExecutionException("AOT generation process finished with exit code: " + exitCode);
|
||||
}
|
||||
JavaProcessExecutor processExecutor = new JavaProcessExecutor(this.session, this.toolchainManager);
|
||||
processExecutor.run(this.project.getBasedir(), args, Collections.emptyMap());
|
||||
}
|
||||
|
||||
private int forkJvm(File workingDirectory, List<String> args, Map<String, String> environmentVariables)
|
||||
throws MojoExecutionException {
|
||||
try {
|
||||
RunProcess runProcess = new RunProcess(workingDirectory, getJavaExecutable());
|
||||
return runProcess.run(true, args, environmentVariables);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new MojoExecutionException("Could not exec java", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected URL[] getClassPathUrls() throws MojoExecutionException {
|
||||
try {
|
||||
List<URL> urls = new ArrayList<>();
|
||||
addUserDefinedDirectories(urls);
|
||||
addProjectClasses(urls);
|
||||
addDependencies(urls, getFilters(new TestArtifactFilter()));
|
||||
return urls.toArray(new URL[0]);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new MojoExecutionException("Unable to build classpath", ex);
|
||||
}
|
||||
private URL[] getClassPathUrls() throws MojoExecutionException {
|
||||
List<URL> urls = new ArrayList<>();
|
||||
urls.add(toURL(this.classesDirectory));
|
||||
urls.addAll(getDependencyURLs(new TestArtifactFilter()));
|
||||
return urls.toArray(URL[]::new);
|
||||
}
|
||||
|
||||
private void compileSourceFiles() throws IOException, MojoExecutionException {
|
||||
@@ -148,7 +194,8 @@ public class AotGenerateMojo extends AbstractRunMojo {
|
||||
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
|
||||
try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) {
|
||||
List<String> options = new ArrayList<>();
|
||||
addClasspath(options);
|
||||
options.add("-cp");
|
||||
options.add(ClasspathBuilder.build(Arrays.asList(getClassPathUrls())));
|
||||
options.add("-d");
|
||||
options.add(this.classesDirectory.toPath().toAbsolutePath().toString());
|
||||
Iterable<? extends JavaFileObject> compilationUnits = fm.getJavaFileObjectsFromPaths(sourceFiles);
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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
|
||||
*
|
||||
* https://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 org.springframework.boot.maven;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Helper class to build the command-line arguments of a java process.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
final class CommandLineBuilder {
|
||||
|
||||
private final List<String> options = new ArrayList<>();
|
||||
|
||||
private final List<URL> classpathElements = new ArrayList<>();
|
||||
|
||||
private final String mainClass;
|
||||
|
||||
private final List<String> arguments = new ArrayList<>();
|
||||
|
||||
private CommandLineBuilder(String mainClass) {
|
||||
this.mainClass = mainClass;
|
||||
}
|
||||
|
||||
static CommandLineBuilder forMainClass(String mainClass) {
|
||||
return new CommandLineBuilder(mainClass);
|
||||
}
|
||||
|
||||
CommandLineBuilder withJvmArguments(String... jvmArguments) {
|
||||
if (jvmArguments != null) {
|
||||
this.options.addAll(Arrays.stream(jvmArguments).filter(Objects::nonNull).toList());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
CommandLineBuilder withSystemProperties(Map<String, String> systemProperties) {
|
||||
if (systemProperties != null) {
|
||||
systemProperties.entrySet().stream().map((e) -> SystemPropertyFormatter.format(e.getKey(), e.getValue()))
|
||||
.forEach(this.options::add);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
CommandLineBuilder withClasspath(URL... elements) {
|
||||
this.classpathElements.addAll(Arrays.asList(elements));
|
||||
return this;
|
||||
}
|
||||
|
||||
CommandLineBuilder withArguments(String... arguments) {
|
||||
if (arguments != null) {
|
||||
this.arguments.addAll(Arrays.stream(arguments).filter(Objects::nonNull).toList());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
List<String> build() {
|
||||
List<String> commandLine = new ArrayList<>();
|
||||
if (!this.options.isEmpty()) {
|
||||
commandLine.addAll(this.options);
|
||||
}
|
||||
if (!this.classpathElements.isEmpty()) {
|
||||
commandLine.add("-cp");
|
||||
commandLine.add(ClasspathBuilder.build(this.classpathElements));
|
||||
}
|
||||
commandLine.add(this.mainClass);
|
||||
if (!this.arguments.isEmpty()) {
|
||||
commandLine.addAll(this.arguments);
|
||||
}
|
||||
return commandLine;
|
||||
}
|
||||
|
||||
static class ClasspathBuilder {
|
||||
|
||||
static String build(List<URL> classpathElements) {
|
||||
StringBuilder classpath = new StringBuilder();
|
||||
for (URL element : classpathElements) {
|
||||
if (classpath.length() > 0) {
|
||||
classpath.append(File.pathSeparator);
|
||||
}
|
||||
classpath.append(toFile(element));
|
||||
}
|
||||
return classpath.toString();
|
||||
}
|
||||
|
||||
private static File toFile(URL element) {
|
||||
try {
|
||||
return new File(element.toURI());
|
||||
}
|
||||
catch (URISyntaxException ex) {
|
||||
throw new IllegalArgumentException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Format System properties.
|
||||
*/
|
||||
private static class SystemPropertyFormatter {
|
||||
|
||||
static String format(String key, String value) {
|
||||
if (key == null) {
|
||||
return "";
|
||||
}
|
||||
if (value == null || value.isEmpty()) {
|
||||
return String.format("-D%s", key);
|
||||
}
|
||||
return String.format("-D%s=\"%s\"", key, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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
|
||||
*
|
||||
* https://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 org.springframework.boot.maven;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.maven.execution.MavenSession;
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
import org.apache.maven.toolchain.Toolchain;
|
||||
import org.apache.maven.toolchain.ToolchainManager;
|
||||
|
||||
import org.springframework.boot.loader.tools.JavaExecutable;
|
||||
import org.springframework.boot.loader.tools.RunProcess;
|
||||
|
||||
/**
|
||||
* Ease the execution of a Java process using Maven's toolchain support.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class JavaProcessExecutor {
|
||||
|
||||
private static final int EXIT_CODE_SIGINT = 130;
|
||||
|
||||
private final MavenSession mavenSession;
|
||||
|
||||
private final ToolchainManager toolchainManager;
|
||||
|
||||
JavaProcessExecutor(MavenSession mavenSession, ToolchainManager toolchainManager) {
|
||||
this.mavenSession = mavenSession;
|
||||
this.toolchainManager = toolchainManager;
|
||||
}
|
||||
|
||||
int run(File workingDirectory, List<String> args, Map<String, String> environmentVariables)
|
||||
throws MojoExecutionException {
|
||||
RunProcess runProcess = new RunProcess(workingDirectory, getJavaExecutable());
|
||||
try {
|
||||
int exitCode = runProcess.run(true, args, environmentVariables);
|
||||
if (!hasTerminatedSuccessfully(exitCode)) {
|
||||
throw new MojoExecutionException("Process terminated with exit code: " + exitCode);
|
||||
}
|
||||
return exitCode;
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new MojoExecutionException("Process execution failed", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasTerminatedSuccessfully(int exitCode) {
|
||||
return (exitCode == 0 || exitCode == EXIT_CODE_SIGINT);
|
||||
}
|
||||
|
||||
private String getJavaExecutable() {
|
||||
Toolchain toolchain = this.toolchainManager.getToolchainFromBuildContext("jdk", this.mavenSession);
|
||||
String javaExecutable = (toolchain != null) ? toolchain.findTool("java") : null;
|
||||
return (javaExecutable != null) ? javaExecutable : new JavaExecutable().toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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
|
||||
*
|
||||
* https://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 org.springframework.boot.maven;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.maven.plugin.MojoExecutionException;
|
||||
|
||||
import org.springframework.boot.loader.tools.MainClassFinder;
|
||||
|
||||
/**
|
||||
* Find a single Spring Boot Application class match based on directory.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @see MainClassFinder
|
||||
*/
|
||||
abstract class SpringBootApplicationClassFinder {
|
||||
|
||||
private static final String SPRING_BOOT_APPLICATION_CLASS_NAME = "org.springframework.boot.autoconfigure.SpringBootApplication";
|
||||
|
||||
static String findSingleClass(File classesDirectory) throws MojoExecutionException {
|
||||
try {
|
||||
String mainClass = MainClassFinder.findSingleMainClass(classesDirectory,
|
||||
SPRING_BOOT_APPLICATION_CLASS_NAME);
|
||||
if (mainClass != null) {
|
||||
return mainClass;
|
||||
}
|
||||
throw new MojoExecutionException("Unable to find a suitable main class, please add a 'mainClass' property");
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new MojoExecutionException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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
|
||||
*
|
||||
* https://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 org.springframework.boot.maven;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.maven.sample.ClassWithMainMethod;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link CommandLineBuilder}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class CommandLineBuilderTests {
|
||||
|
||||
public static final String CLASS_NAME = ClassWithMainMethod.class.getName();
|
||||
|
||||
@Test
|
||||
void buildWithNullJvmArgumentsIsIgnored() {
|
||||
assertThat(CommandLineBuilder.forMainClass(CLASS_NAME).withJvmArguments((String[]) null).build())
|
||||
.containsExactly(CLASS_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildWithNullIntermediateJvmArgumentIsIgnored() {
|
||||
assertThat(CommandLineBuilder.forMainClass(CLASS_NAME).withJvmArguments("-verbose:class", null, "-verbose:gc")
|
||||
.build()).containsExactly("-verbose:class", "-verbose:gc", CLASS_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildWithJvmArgument() {
|
||||
assertThat(CommandLineBuilder.forMainClass(CLASS_NAME).withJvmArguments("-verbose:class").build())
|
||||
.containsExactly("-verbose:class", CLASS_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildWithNullSystemPropertyIsIgnored() {
|
||||
assertThat(CommandLineBuilder.forMainClass(CLASS_NAME).withSystemProperties(null).build())
|
||||
.containsExactly(CLASS_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildWithSystemProperty() {
|
||||
assertThat(CommandLineBuilder.forMainClass(CLASS_NAME).withSystemProperties(Map.of("flag", "enabled")).build())
|
||||
.containsExactly("-Dflag=\"enabled\"", CLASS_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildWithNullArgumentsIsIgnored() {
|
||||
assertThat(CommandLineBuilder.forMainClass(CLASS_NAME).withArguments((String[]) null).build())
|
||||
.containsExactly(CLASS_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildWithNullIntermediateArgumentIsIgnored() {
|
||||
assertThat(CommandLineBuilder.forMainClass(CLASS_NAME).withArguments("--test", null, "--another").build())
|
||||
.containsExactly(CLASS_NAME, "--test", "--another");
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user