Use a convention mapping for resolving main class from the classpath
This commit is contained in:
@@ -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;
|
||||
public MainClassResolver(FileCollection classpath) {
|
||||
this.classpath = classpath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get() {
|
||||
if (this.mainClass == null) {
|
||||
this.mainClass = findMainClass();
|
||||
}
|
||||
return this.mainClass;
|
||||
}
|
||||
|
||||
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();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user