Commit bc543ef0 authored by Andy Wilkinson's avatar Andy Wilkinson

Use a convention mapping for resolving main class from the classpath

parent d9af21ab
......@@ -19,52 +19,40 @@ 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;
import org.springframework.boot.loader.tools.MainClassFinder;
/**
* Supplies the main class for an application by returning a configured main class if
* available. If a main class is not available, directories in the application's classpath
* are searched.
* Resolves the main class for an application.
*
* @author Andy Wilkinson
*/
public class MainClassSupplier implements Supplier<String> {
public class MainClassResolver {
private static final String SPRING_BOOT_APPLICATION_CLASS_NAME = "org.springframework.boot.autoconfigure.SpringBootApplication";
private final Supplier<FileCollection> classpathSupplier;
private String mainClass;
private final FileCollection classpath;
/**
* Creates a new {@code MainClassSupplier} that will fall back to searching
* directories in the classpath supplied by the given {@code classpathSupplier} for
* Creates a new {@code MainClassResolver} that will search
* directories in the given {@code classpath} for
* the application's main class.
*
* @param classpathSupplier the supplier of the classpath
* @param classpath the classpath
*/
public MainClassSupplier(Supplier<FileCollection> classpathSupplier) {
this.classpathSupplier = classpathSupplier;
}
@Override
public String get() {
if (this.mainClass == null) {
this.mainClass = findMainClass();
}
return this.mainClass;
public MainClassResolver(FileCollection classpath) {
this.classpath = classpath;
}
private String findMainClass() {
FileCollection classpath = this.classpathSupplier.get();
if (classpath == null) {
return null;
}
return classpath.filter(File::isDirectory).getFiles().stream()
/**
* Resolves the main class.
*
* @return the main class or {@code null}
*/
public String resolveMainClass() {
return this.classpath.filter(File::isDirectory).getFiles().stream()
.map(this::findMainClass).filter(Objects::nonNull).findFirst()
.orElse(null);
}
......@@ -80,13 +68,4 @@ public class MainClassSupplier implements Supplier<String> {
}
}
/**
* Sets the {@code mainClass} that will be supplied.
*
* @param mainClass the main class to supply
*/
public void setMainClass(String mainClass) {
this.mainClass = mainClass;
}
}
......@@ -37,25 +37,21 @@ class BootArchiveSupport {
private final PatternSet requiresUnpack = new PatternSet();
private final MainClassSupplier mainClassSupplier;
private final Set<String> storedPathPrefixes;
private String loaderMainClass;
private LaunchScriptConfiguration launchScript = new LaunchScriptConfiguration();
BootArchiveSupport(MainClassSupplier mainClassSupplier,
String... storedPathPrefixes) {
this.mainClassSupplier = mainClassSupplier;
BootArchiveSupport(String... storedPathPrefixes) {
this.storedPathPrefixes = new HashSet<>(Arrays.asList(storedPathPrefixes));
this.requiresUnpack.include(Specs.satisfyNone());
}
void configureManifest(Jar jar) {
void configureManifest(Jar jar, String mainClass) {
Attributes attributes = jar.getManifest().getAttributes();
attributes.putIfAbsent("Main-Class", this.loaderMainClass);
attributes.putIfAbsent("Start-Class", this.mainClassSupplier.get());
attributes.putIfAbsent("Start-Class", mainClass);
}
CopyAction createCopyAction(Jar jar) {
......
......@@ -28,8 +28,6 @@ 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.
*
......@@ -37,10 +35,7 @@ import org.springframework.boot.gradle.MainClassSupplier;
*/
public class BootJar extends Jar implements BootArchive {
private final MainClassSupplier mainClassSupplier = new MainClassSupplier(
this::getClasspath);
private BootArchiveSupport support = new BootArchiveSupport(this.mainClassSupplier, "BOOT-INF/lib");
private BootArchiveSupport support = new BootArchiveSupport("BOOT-INF/lib");
private FileCollection classpath;
......@@ -65,7 +60,7 @@ public class BootJar extends Jar implements BootArchive {
@Override
public void copy() {
this.support.configureManifest(this);
this.support.configureManifest(this, getMainClass());
super.copy();
}
......@@ -82,7 +77,6 @@ public class BootJar extends Jar implements BootArchive {
@Override
public void setMainClass(String mainClass) {
this.mainClass = mainClass;
this.mainClassSupplier.setMainClass(mainClass);
}
@Override
......
......@@ -29,8 +29,6 @@ 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.
*
......@@ -38,11 +36,8 @@ import org.springframework.boot.gradle.MainClassSupplier;
*/
public class BootWar extends War implements BootArchive {
private final MainClassSupplier mainClassSupplier = new MainClassSupplier(
this::getClasspath);
private final BootArchiveSupport support = new BootArchiveSupport(
this.mainClassSupplier, "WEB-INF/lib/", "WEB-INF/lib-provided");
private final BootArchiveSupport support = new BootArchiveSupport("WEB-INF/lib/",
"WEB-INF/lib-provided");
private String mainClass;
......@@ -60,7 +55,7 @@ public class BootWar extends War implements BootArchive {
@Override
public void copy() {
this.support.configureManifest(this);
this.support.configureManifest(this, getMainClass());
super.copy();
}
......@@ -77,7 +72,6 @@ public class BootWar extends War implements BootArchive {
@Override
public void setMainClass(String mainClass) {
this.mainClass = mainClass;
this.mainClassSupplier.setMainClass(mainClass);
}
@Override
......
......@@ -37,6 +37,7 @@ import org.gradle.api.plugins.WarPlugin;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.Upload;
import org.springframework.boot.gradle.MainClassResolver;
import org.springframework.boot.gradle.PluginFeatures;
/**
......@@ -65,6 +66,9 @@ public class BundlingPluginFeatures implements PluginFeatures {
ArchivePublishArtifact artifact = new ArchivePublishArtifact(bootWar);
this.singlePublishedArtifact.addCandidate(artifact);
project.getComponents().add(new BootSoftwareComponent(artifact, "bootWeb"));
bootWar.conventionMapping("mainClass", () -> {
return new MainClassResolver(bootWar.getClasspath()).resolveMainClass();
});
}
private void configureBootJarTask(Project project) {
......@@ -79,6 +83,9 @@ public class BundlingPluginFeatures implements PluginFeatures {
ArchivePublishArtifact artifact = new ArchivePublishArtifact(bootJar);
this.singlePublishedArtifact.addCandidate(artifact);
project.getComponents().add(new BootSoftwareComponent(artifact, "bootJava"));
bootJar.conventionMapping("mainClass", () -> {
return new MainClassResolver(bootJar.getClasspath()).resolveMainClass();
});
}
private void configureBootArchivesUpload(Project project) {
......
......@@ -26,7 +26,6 @@ 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;
/**
......@@ -38,9 +37,6 @@ import org.springframework.boot.loader.tools.FileUtils;
*/
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
......@@ -67,17 +63,6 @@ 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());
......
......@@ -23,6 +23,7 @@ import org.gradle.api.Project;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginConvention;
import org.springframework.boot.gradle.MainClassResolver;
import org.springframework.boot.gradle.PluginFeatures;
/**
......@@ -60,6 +61,9 @@ public class RunPluginFeatures implements PluginFeatures {
return Collections.emptyList();
}
});
run.conventionMapping("main", () -> {
return new MainClassResolver(run.getClasspath()).resolveMainClass();
});
}
}
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