diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/MainClassSupplier.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/MainClassSupplier.java similarity index 55% rename from spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/MainClassSupplier.java rename to spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/MainClassSupplier.java index 1e6a76b4eb..0b493f1a67 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/MainClassSupplier.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/MainClassSupplier.java @@ -14,10 +14,11 @@ * limitations under the License. */ -package org.springframework.boot.gradle.bundling; +package org.springframework.boot.gradle; import java.io.File; import java.io.IOException; +import java.util.Objects; import java.util.function.Supplier; import org.gradle.api.file.FileCollection; @@ -31,41 +32,60 @@ import org.springframework.boot.loader.tools.MainClassFinder; * * @author Andy Wilkinson */ -class MainClassSupplier implements Supplier { +public class MainClassSupplier implements Supplier { + + private static final String SPRING_BOOT_APPLICATION_CLASS_NAME = "org.springframework.boot.autoconfigure.SpringBootApplication"; private final Supplier classpathSupplier; private String mainClass; - MainClassSupplier(Supplier classpathSupplier) { + /** + * Creates a new {@code MainClassSupplier} that will fall back to searching + * directories in the classpath supplied by the given {@code classpathSupplier} for + * the application's main class. + * + * @param classpathSupplier the supplier of the classpath + */ + public MainClassSupplier(Supplier classpathSupplier) { this.classpathSupplier = classpathSupplier; } @Override public String get() { - if (this.mainClass != null) { - return this.mainClass; + if (this.mainClass == null) { + this.mainClass = findMainClass(); } - return findMainClass(); + return this.mainClass; } private String findMainClass() { FileCollection classpath = this.classpathSupplier.get(); - return classpath == null ? null - : classpath.filter(File::isDirectory).getFiles().stream() - .map(this::findMainClass).findFirst().orElse(null); + if (classpath == null) { + return null; + } + return classpath.filter(File::isDirectory).getFiles().stream() + .map(this::findMainClass).filter(Objects::nonNull).findFirst() + .orElse(null); } private String findMainClass(File file) { try { - return MainClassFinder.findSingleMainClass(file); + String result = MainClassFinder.findSingleMainClass(file, + SPRING_BOOT_APPLICATION_CLASS_NAME); + return result; } catch (IOException ex) { return null; } } - void setMainClass(String mainClass) { + /** + * Sets the {@code mainClass} that will be supplied. + * + * @param mainClass the main class to supply + */ + public void setMainClass(String mainClass) { this.mainClass = mainClass; } diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/BootJar.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/BootJar.java index 3a118c8e6e..03aaeaaaeb 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/BootJar.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/BootJar.java @@ -28,6 +28,8 @@ import org.gradle.api.internal.file.copy.CopyAction; import org.gradle.api.specs.Spec; import org.gradle.api.tasks.bundling.Jar; +import org.springframework.boot.gradle.MainClassSupplier; + /** * A custom {@link Jar} task that produces a Spring Boot executable jar. * diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/BootWar.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/BootWar.java index dddebe0777..33f425ed19 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/BootWar.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/BootWar.java @@ -29,6 +29,8 @@ import org.gradle.api.specs.Spec; import org.gradle.api.tasks.Optional; import org.gradle.api.tasks.bundling.War; +import org.springframework.boot.gradle.MainClassSupplier; + /** * A custom {@link War} task that produces a Spring Boot executable war. * diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/BootRunTask.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/BootRunTask.java index 7f51972f9f..9f40aacdb9 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/BootRunTask.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/BootRunTask.java @@ -26,6 +26,7 @@ import org.gradle.api.internal.file.collections.SimpleFileCollection; import org.gradle.api.tasks.JavaExec; import org.gradle.api.tasks.SourceSet; +import org.springframework.boot.gradle.MainClassSupplier; import org.springframework.boot.loader.tools.FileUtils; /** @@ -33,9 +34,13 @@ import org.springframework.boot.loader.tools.FileUtils; * * @author Dave Syer * @author Phillip Webb + * @author Andy Wilkinson */ public class BootRunTask extends JavaExec { + private final MainClassSupplier mainClassSupplier = new MainClassSupplier( + this::getClasspath); + /** * Whether or not resources (typically in {@code src/main/resources} are added * directly to the classpath. When enabled, this allows live in-place editing of @@ -62,6 +67,17 @@ public class BootRunTask extends JavaExec { super.exec(); } + @Override + public String getMain() { + return this.mainClassSupplier.get(); + } + + @Override + public JavaExec setMain(String mainClassName) { + this.mainClassSupplier.setMainClass(mainClassName); + return super.setMain(mainClassName); + } + private void addResourcesIfNecessary() { if (this.addResources) { SourceSet mainSourceSet = SourceSets.findMainSourceSet(getProject()); diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/FindMainClassTask.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/FindMainClassTask.java deleted file mode 100644 index c3d2470a92..0000000000 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/FindMainClassTask.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright 2012-2016 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 org.springframework.boot.gradle.run; - -import java.io.IOException; - -import org.gradle.api.DefaultTask; -import org.gradle.api.Project; -import org.gradle.api.Task; -import org.gradle.api.plugins.ApplicationPluginConvention; -import org.gradle.api.plugins.ExtraPropertiesExtension; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.JavaExec; -import org.gradle.api.tasks.SourceSetOutput; -import org.gradle.api.tasks.TaskAction; - -import org.springframework.boot.gradle.SpringBootPluginExtension; -import org.springframework.boot.loader.tools.MainClassFinder; - -/** - * Task to find and set the 'mainClassName' convention when it's missing by searching the - * main source code. - * - * @author Dave Syer - * @author Phillip Webb - * @author Andy Wilkinson - */ -public class FindMainClassTask extends DefaultTask { - - private static final String SPRING_BOOT_APPLICATION_CLASS_NAME = "org.springframework.boot.autoconfigure.SpringBootApplication"; - - @Input - private SourceSetOutput mainClassSourceSetOutput; - - public void setMainClassSourceSetOutput(SourceSetOutput sourceSetOutput) { - this.mainClassSourceSetOutput = sourceSetOutput; - this.dependsOn(this.mainClassSourceSetOutput.getBuildDependencies()); - } - - @TaskAction - public void setMainClassNameProperty() { - Project project = getProject(); - if (!project.hasProperty("mainClassName") - || project.property("mainClassName") == null) { - String mainClass = findMainClass(); - if (project.hasProperty("mainClassName")) { - project.setProperty("mainClassName", mainClass); - } - else { - ExtraPropertiesExtension extraProperties = (ExtraPropertiesExtension) project - .getExtensions().getByName("ext"); - extraProperties.set("mainClassName", mainClass); - } - } - } - - private String findMainClass() { - Project project = getProject(); - - String mainClass = null; - - // Try the SpringBoot extension setting - SpringBootPluginExtension bootExtension = project.getExtensions() - .getByType(SpringBootPluginExtension.class); - if (bootExtension.getMainClass() != null) { - mainClass = bootExtension.getMainClass(); - } - - ApplicationPluginConvention application = (ApplicationPluginConvention) project - .getConvention().getPlugins().get("application"); - - if (mainClass == null && application != null) { - // Try the Application extension setting - mainClass = application.getMainClassName(); - } - - JavaExec runTask = findRunTask(project); - if (mainClass == null && runTask != null) { - mainClass = runTask.getMain(); - } - - if (mainClass == null) { - Task bootRunTask = project.getTasks().findByName("bootRun"); - if (bootRunTask != null) { - mainClass = (String) bootRunTask.property("main"); - } - } - - if (mainClass == null) { - // Search - if (this.mainClassSourceSetOutput != null) { - project.getLogger().debug("Looking for main in: " - + this.mainClassSourceSetOutput.getClassesDir()); - try { - mainClass = MainClassFinder.findSingleMainClass( - this.mainClassSourceSetOutput.getClassesDir(), - SPRING_BOOT_APPLICATION_CLASS_NAME); - project.getLogger().info("Computed main class: " + mainClass); - } - catch (IOException ex) { - throw new IllegalStateException("Cannot find main class", ex); - } - } - } - - project.getLogger().info("Found main: " + mainClass); - - if (bootExtension.getMainClass() == null) { - bootExtension.setMainClass(mainClass); - } - if (application != null && application.getMainClassName() == null) { - application.setMainClassName(mainClass); - } - if (runTask != null && !runTask.hasProperty("main")) { - runTask.setMain(mainClass); - } - - return mainClass; - } - - private JavaExec findRunTask(Project project) { - Task runTask = project.getTasks().findByName("run"); - if (runTask instanceof JavaExec) { - return (JavaExec) runTask; - } - return null; - } - -} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/RunPluginFeatures.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/RunPluginFeatures.java index 4ac2b1e507..41b335b83e 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/RunPluginFeatures.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/RunPluginFeatures.java @@ -19,14 +19,9 @@ package org.springframework.boot.gradle.run; import java.util.Collections; import java.util.concurrent.Callable; -import org.gradle.api.Action; import org.gradle.api.Project; -import org.gradle.api.Task; -import org.gradle.api.plugins.ExtraPropertiesExtension; import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.plugins.JavaPluginConvention; -import org.gradle.api.tasks.SourceSet; -import org.gradle.api.tasks.application.CreateStartScripts; import org.springframework.boot.gradle.PluginFeatures; @@ -37,35 +32,15 @@ import org.springframework.boot.gradle.PluginFeatures; */ public class RunPluginFeatures implements PluginFeatures { - private static final String FIND_MAIN_CLASS_TASK_NAME = "findMainClass"; - private static final String RUN_APP_TASK_NAME = "bootRun"; @Override public void apply(Project project) { project.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> { - mainClassNameFinder(project); addBootRunTask(project); }); } - private void mainClassNameFinder(Project project) { - FindMainClassTask findMainClassTask = project.getTasks() - .create(FIND_MAIN_CLASS_TASK_NAME, FindMainClassTask.class); - SourceSet mainSourceSet = SourceSets.findMainSourceSet(project); - if (mainSourceSet != null) { - findMainClassTask.setMainClassSourceSetOutput(mainSourceSet.getOutput()); - } - project.getTasks().all(new Action() { - @Override - public void execute(Task task) { - if (task instanceof BootRunTask || task instanceof CreateStartScripts) { - task.dependsOn(FIND_MAIN_CLASS_TASK_NAME); - } - } - }); - } - private void addBootRunTask(final Project project) { final JavaPluginConvention javaConvention = project.getConvention() .getPlugin(JavaPluginConvention.class); @@ -76,22 +51,6 @@ public class RunPluginFeatures implements PluginFeatures { run.setGroup("application"); run.setClasspath( javaConvention.getSourceSets().findByName("main").getRuntimeClasspath()); - run.getConventionMapping().map("main", new Callable() { - @Override - public Object call() throws Exception { - if (project.hasProperty("mainClassName") - && project.property("mainClassName") != null) { - return project.property("mainClassName"); - } - ExtraPropertiesExtension extraPropertiesExtension = (ExtraPropertiesExtension) project - .getExtensions().getByName("ext"); - if (extraPropertiesExtension.has("mainClassName") - && extraPropertiesExtension.get("mainClassName") != null) { - return extraPropertiesExtension.get("mainClassName"); - } - return null; - } - }); run.getConventionMapping().map("jvmArgs", new Callable() { @Override public Object call() throws Exception {