Commit b4e2044b authored by Andy Wilkinson's avatar Andy Wilkinson

Simplify bootRun main class configuration by reusing MainClassSupplier

parent f16efb22
......@@ -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<String> {
public class MainClassSupplier implements Supplier<String> {
private static final String SPRING_BOOT_APPLICATION_CLASS_NAME = "org.springframework.boot.autoconfigure.SpringBootApplication";
private final Supplier<FileCollection> classpathSupplier;
private String mainClass;
MainClassSupplier(Supplier<FileCollection> 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<FileCollection> 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;
}
......
......@@ -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.
*
......
......@@ -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.
*
......
......@@ -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());
......
/*
* 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;
}
}
......@@ -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<Task>() {
@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<Object>() {
@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<Object>() {
@Override
public Object call() throws Exception {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment