diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractApplicationRunMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractApplicationRunMojo.java deleted file mode 100644 index 578162b4c5..0000000000 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractApplicationRunMojo.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * 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.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -import org.apache.maven.model.Resource; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.MojoFailureException; -import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.shared.artifact.filter.collection.FilterArtifacts; - -import org.springframework.boot.loader.tools.FileUtils; - -/** - * Base class to run a spring application. - * - * @author Phillip Webb - * @author Stephane Nicoll - * @author David Liu - * @author Daniel Young - * @author Dmytro Nosan - * @since 3.0.0 - * @see RunMojo - * @see StartMojo - */ -public abstract class AbstractApplicationRunMojo extends AbstractRunMojo { - - /** - * Add maven resources to the classpath directly, this allows live in-place editing of - * resources. Duplicate resources are removed from {@code target/classes} to prevent - * them to appear twice if {@code ClassLoader.getResources()} is called. Please - * consider adding {@code spring-boot-devtools} to your project instead as it provides - * this feature and many more. - * @since 1.0.0 - */ - @Parameter(property = "spring-boot.run.addResources", defaultValue = "false") - private boolean addResources = false; - - /** - * Path to agent jars. NOTE: a forked process is required to use this feature. - * @since 2.2.0 - */ - @Parameter(property = "spring-boot.run.agents") - private File[] agents; - - /** - * Flag to say that the agent requires -noverify. - * @since 1.0.0 - */ - @Parameter(property = "spring-boot.run.noverify") - private boolean noverify = false; - - /** - * Flag to include the test classpath when running. - * @since 1.3.0 - */ - @Parameter(property = "spring-boot.run.useTestClasspath", defaultValue = "false") - private Boolean useTestClasspath; - - @Override - protected void run(File workingDirectory, String startClassName, Map environmentVariables) - throws MojoExecutionException, MojoFailureException { - List args = new ArrayList<>(); - addAgents(args); - addJvmArgs(args); - addClasspath(args); - args.add(startClassName); - addArgs(args); - run(workingDirectory, args, environmentVariables); - } - - /** - * Run with a forked VM, using the specified command line arguments. - * @param workingDirectory the working directory of the forked JVM - * @param args the arguments (JVM arguments and application arguments) - * @param environmentVariables the environment variables - * @throws MojoExecutionException in case of MOJO execution errors - * @throws MojoFailureException in case of MOJO failures - */ - protected abstract void run(File workingDirectory, List args, Map environmentVariables) - throws MojoExecutionException, MojoFailureException; - - @Override - protected URL[] getClassPathUrls() throws MojoExecutionException { - try { - List urls = new ArrayList<>(); - addUserDefinedDirectories(urls); - addResources(urls); - addProjectClasses(urls); - FilterArtifacts filters = (this.useTestClasspath ? getFilters() : getFilters(new TestArtifactFilter())); - addDependencies(urls, filters); - return urls.toArray(new URL[0]); - } - catch (IOException ex) { - throw new MojoExecutionException("Unable to build classpath", ex); - } - } - - private void addAgents(List args) { - if (this.agents != null) { - if (getLog().isInfoEnabled()) { - getLog().info("Attaching agents: " + Arrays.asList(this.agents)); - } - for (File agent : this.agents) { - args.add("-javaagent:" + agent); - } - } - if (this.noverify) { - args.add("-noverify"); - } - } - - private void addResources(List urls) throws IOException { - if (this.addResources) { - for (Resource resource : this.project.getResources()) { - File directory = new File(resource.getDirectory()); - urls.add(directory.toURI().toURL()); - FileUtils.removeDuplicatesFromOutputDirectory(this.classesDirectory, directory); - } - } - } - -} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java index 20b294ec51..a203f79fca 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java @@ -20,6 +20,7 @@ import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -29,21 +30,22 @@ import java.util.stream.Collectors; import org.apache.maven.artifact.Artifact; import org.apache.maven.execution.MavenSession; +import org.apache.maven.model.Resource; 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.Parameter; import org.apache.maven.project.MavenProject; -import org.apache.maven.shared.artifact.filter.collection.AbstractArtifactFeatureFilter; import org.apache.maven.shared.artifact.filter.collection.FilterArtifacts; import org.apache.maven.toolchain.Toolchain; import org.apache.maven.toolchain.ToolchainManager; +import org.springframework.boot.loader.tools.FileUtils; import org.springframework.boot.loader.tools.JavaExecutable; import org.springframework.boot.loader.tools.MainClassFinder; /** - * Base class to support running a process that deals with a Spring application. + * Base class to run a Spring Boot application. * * @author Phillip Webb * @author Stephane Nicoll @@ -51,19 +53,19 @@ import org.springframework.boot.loader.tools.MainClassFinder; * @author Daniel Young * @author Dmytro Nosan * @since 1.3.0 + * @see RunMojo + * @see StartMojo */ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { private static final String SPRING_BOOT_APPLICATION_CLASS_NAME = "org.springframework.boot.autoconfigure.SpringBootApplication"; - private static final int EXIT_CODE_SIGINT = 130; - /** * The Maven project. * @since 1.0.0 */ @Parameter(defaultValue = "${project}", readonly = true, required = true) - protected MavenProject project; + private MavenProject project; /** * The current Maven session. This is used for toolchain manager API calls. @@ -79,6 +81,31 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { @Component private ToolchainManager toolchainManager; + /** + * Add maven resources to the classpath directly, this allows live in-place editing of + * resources. Duplicate resources are removed from {@code target/classes} to prevent + * them to appear twice if {@code ClassLoader.getResources()} is called. Please + * consider adding {@code spring-boot-devtools} to your project instead as it provides + * this feature and many more. + * @since 1.0.0 + */ + @Parameter(property = "spring-boot.run.addResources", defaultValue = "false") + private boolean addResources = false; + + /** + * Path to agent jars. + * @since 2.2.0 + */ + @Parameter(property = "spring-boot.run.agents") + private File[] agents; + + /** + * Flag to say that the agent requires -noverify. + * @since 1.0.0 + */ + @Parameter(property = "spring-boot.run.noverify") + private boolean noverify = false; + /** * Current working directory to use for the application. If not specified, basedir * will be used. @@ -157,7 +184,14 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { * @since 1.0.0 */ @Parameter(defaultValue = "${project.build.outputDirectory}", required = true) - protected File classesDirectory; + private File classesDirectory; + + /** + * Flag to include the test classpath when running. + * @since 1.3.0 + */ + @Parameter(property = "spring-boot.run.useTestClasspath", defaultValue = "false") + private Boolean useTestClasspath; /** * Skip the execution. @@ -172,30 +206,31 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { getLog().debug("skipping run as per configuration."); return; } - run((this.workingDirectory != null) ? this.workingDirectory : this.project.getBasedir(), getStartClass(), + run(getStartClass()); + } + + private void run(String startClassName) throws MojoExecutionException, MojoFailureException { + List args = new ArrayList<>(); + addAgents(args); + addJvmArgs(args); + addClasspath(args); + args.add(startClassName); + addArgs(args); + run((this.workingDirectory != null) ? this.workingDirectory : this.project.getBasedir(), args, determineEnvironmentVariables()); } /** - * Run with a forked VM, using the specified class name. + * Run with a forked VM, using the specified command line arguments. * @param workingDirectory the working directory of the forked JVM - * @param startClassName the name of the class to execute + * @param args the arguments (JVM arguments and application arguments) * @param environmentVariables the environment variables * @throws MojoExecutionException in case of MOJO execution errors * @throws MojoFailureException in case of MOJO failures */ - protected abstract void run(File workingDirectory, String startClassName, Map environmentVariables) + protected abstract void run(File workingDirectory, List args, Map environmentVariables) throws MojoExecutionException, MojoFailureException; - /** - * Specify if the forked process has terminated successfully, based on its exit code. - * @param exitCode the exit code of the process - * @return {@code true} if the process has terminated successfully - */ - protected boolean hasTerminatedSuccessfully(int exitCode) { - return (exitCode == 0 || exitCode == EXIT_CODE_SIGINT); - } - /** * Resolve the application arguments to use. * @return a {@link RunArguments} defining the application arguments @@ -225,7 +260,7 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { return new EnvVariables(this.environmentVariables); } - protected void addArgs(List args) { + private void addArgs(List args) { RunArguments applicationArguments = resolveApplicationArguments(); Collections.addAll(args, applicationArguments.asArray()); logArguments("Application argument(s): ", applicationArguments.asArray()); @@ -254,12 +289,26 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { return new RunArguments(stringBuilder.toString()); } - protected void addJvmArgs(List args) { + private void addJvmArgs(List args) { RunArguments jvmArguments = resolveJvmArguments(); Collections.addAll(args, jvmArguments.asArray()); logArguments("JVM argument(s): ", jvmArguments.asArray()); } + private void addAgents(List args) { + if (this.agents != null) { + if (getLog().isInfoEnabled()) { + getLog().info("Attaching agents: " + Arrays.asList(this.agents)); + } + for (File agent : this.agents) { + args.add("-javaagent:" + agent); + } + } + if (this.noverify) { + args.add("-noverify"); + } + } + private void addActiveProfileArgument(RunArguments arguments) { if (this.profiles.length > 0) { StringBuilder arg = new StringBuilder("--spring.profiles.active="); @@ -274,7 +323,7 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { } } - protected void addClasspath(List args) throws MojoExecutionException { + private void addClasspath(List args) throws MojoExecutionException { try { StringBuilder classpath = new StringBuilder(); for (URL ele : getClassPathUrls()) { @@ -294,7 +343,7 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { } } - protected String getStartClass() throws MojoExecutionException { + private String getStartClass() throws MojoExecutionException { String mainClass = this.mainClass; if (mainClass == null) { try { @@ -311,9 +360,21 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { return mainClass; } - protected abstract URL[] getClassPathUrls() throws MojoExecutionException; + protected URL[] getClassPathUrls() throws MojoExecutionException { + try { + List urls = new ArrayList<>(); + addUserDefinedDirectories(urls); + addResources(urls); + addProjectClasses(urls); + addDependencies(urls); + return urls.toArray(new URL[0]); + } + catch (IOException ex) { + throw new MojoExecutionException("Unable to build classpath", ex); + } + } - protected void addUserDefinedDirectories(List urls) throws MalformedURLException { + private void addUserDefinedDirectories(List urls) throws MalformedURLException { if (this.directories != null) { for (String directory : this.directories) { urls.add(new File(directory).toURI().toURL()); @@ -321,12 +382,22 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { } } - protected void addProjectClasses(List urls) throws MalformedURLException { + private void addResources(List urls) throws IOException { + if (this.addResources) { + for (Resource resource : this.project.getResources()) { + File directory = new File(resource.getDirectory()); + urls.add(directory.toURI().toURL()); + FileUtils.removeDuplicatesFromOutputDirectory(this.classesDirectory, directory); + } + } + } + + private void addProjectClasses(List urls) throws MalformedURLException { urls.add(this.classesDirectory.toURI().toURL()); } - protected void addDependencies(List urls, FilterArtifacts filters) - throws MalformedURLException, MojoExecutionException { + private void addDependencies(List urls) throws MalformedURLException, MojoExecutionException { + FilterArtifacts filters = (this.useTestClasspath ? getFilters() : getFilters(new TestArtifactFilter())); Set artifacts = filterDependencies(this.project.getArtifacts(), filters); for (Artifact artifact : artifacts) { if (artifact.getFile() != null) { @@ -341,19 +412,6 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo { } } - static class TestArtifactFilter extends AbstractArtifactFeatureFilter { - - TestArtifactFilter() { - super("", Artifact.SCOPE_TEST); - } - - @Override - protected String getArtifactFeature(Artifact artifact) { - return artifact.getScope(); - } - - } - /** * Format System properties. */ diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java index eb2ff574d2..6cc51b7706 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java @@ -41,7 +41,9 @@ import org.springframework.boot.loader.tools.RunProcess; @Mojo(name = "run", requiresProject = true, defaultPhase = LifecyclePhase.VALIDATE, requiresDependencyResolution = ResolutionScope.TEST) @Execute(phase = LifecyclePhase.TEST_COMPILE) -public class RunMojo extends AbstractApplicationRunMojo { +public class RunMojo extends AbstractRunMojo { + + private static final int EXIT_CODE_SIGINT = 130; /** * Whether the JVM's launch should be optimized. @@ -63,7 +65,7 @@ public class RunMojo extends AbstractApplicationRunMojo { protected void run(File workingDirectory, List args, Map environmentVariables) throws MojoExecutionException { int exitCode = forkJvm(workingDirectory, args, environmentVariables); - if (hasTerminatedSuccessfully(exitCode)) { + if (exitCode == 0 || exitCode == EXIT_CODE_SIGINT) { return; } throw new MojoExecutionException("Application finished with exit code: " + exitCode); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java index 4be3b565ef..afedb82554 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java @@ -49,7 +49,7 @@ import org.springframework.boot.loader.tools.RunProcess; */ @Mojo(name = "start", requiresProject = true, defaultPhase = LifecyclePhase.PRE_INTEGRATION_TEST, requiresDependencyResolution = ResolutionScope.TEST) -public class StartMojo extends AbstractApplicationRunMojo { +public class StartMojo extends AbstractRunMojo { private static final String ENABLE_MBEAN_PROPERTY = "--spring.application.admin.enabled=true";