added support for Java 8
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
import java.util.jar.Attributes
|
||||
|
||||
plugins {
|
||||
id "net.woggioni.gradle.multi-release-jar"
|
||||
id 'net.woggioni.gradle.multi-release-jar'
|
||||
}
|
||||
|
||||
ext.setProperty("jpms.module.name", "net.woggioni.envelope")
|
||||
ext {
|
||||
setProperty('jpms.module.name', 'net.woggioni.envelope')
|
||||
}
|
||||
|
||||
configurations {
|
||||
embedded {
|
||||
@@ -28,18 +29,11 @@ java {
|
||||
modularity.inferModulePath = true
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
javaCompiler = javaToolchains.compilerFor {
|
||||
languageVersion = JavaLanguageVersion.of(16)
|
||||
}
|
||||
options.forkOptions.jvmArgs << "--illegal-access=permit"
|
||||
}
|
||||
|
||||
jar {
|
||||
manifest {
|
||||
attributes([
|
||||
(Attributes.Name.SPECIFICATION_TITLE) : "envelope-launcher",
|
||||
(Attributes.Name.SEALED) : true
|
||||
(Attributes.Name.SPECIFICATION_TITLE) : "envelope-launcher",
|
||||
(Attributes.Name.SEALED) : true
|
||||
].collectEntries {
|
||||
[it.key.toString(), it.value.toString()]
|
||||
})
|
||||
@@ -62,13 +56,6 @@ Provider<Tar> tarTaskProvider = tasks.register("tar", Tar) {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named(JavaPlugin.COMPILE_JAVA_TASK_NAME, JavaCompile) {
|
||||
doFirst {
|
||||
String path = project(":common").extensions.getByType(JavaPluginExtension).sourceSets.named("main").get().output.asPath
|
||||
options.compilerArgs.addAll(["--patch-module", "net.woggioni.envelope=$path"])
|
||||
}
|
||||
}
|
||||
|
||||
artifacts {
|
||||
tar tarTaskProvider
|
||||
}
|
@@ -0,0 +1,86 @@
|
||||
package net.woggioni.envelope;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.lang.module.Configuration;
|
||||
import java.lang.module.ModuleFinder;
|
||||
import java.lang.module.ResolvedModule;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Optional;
|
||||
import java.util.Enumeration;
|
||||
import java.util.function.Consumer;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import net.woggioni.xclassloader.ModuleClassLoader;
|
||||
import net.woggioni.xclassloader.JarFileModuleFinder;
|
||||
import net.woggioni.xclassloader.jar.JarFile;
|
||||
import java.util.jar.JarEntry;
|
||||
|
||||
class MainRunner {
|
||||
|
||||
@SneakyThrows
|
||||
static void run(JarFile currentJarFile,
|
||||
String mainModuleName,
|
||||
String mainClassName,
|
||||
String librariesFolder,
|
||||
Consumer<Class<?>> runner) {
|
||||
if(mainModuleName == null) {
|
||||
List<URL> jarList = new ArrayList<>();
|
||||
Enumeration<JarEntry> entries = currentJarFile.entries();
|
||||
while(entries.hasMoreElements()) {
|
||||
JarEntry entry = entries.nextElement();
|
||||
String name = entry.getName();
|
||||
if(!entry.isDirectory() && name.startsWith(librariesFolder) && name.endsWith(".jar")) {
|
||||
jarList.add(currentJarFile.getNestedJarFile(entry).getUrl());
|
||||
}
|
||||
}
|
||||
try (URLClassLoader cl = new URLClassLoader(jarList.toArray(new URL[0]), ClassLoader.getSystemClassLoader().getParent())) {
|
||||
Thread.currentThread().setContextClassLoader(cl);
|
||||
runner.accept(cl.loadClass(mainClassName));
|
||||
}
|
||||
} else {
|
||||
List<JarFile> jarList = new ArrayList<>();
|
||||
Enumeration<JarEntry> entries = currentJarFile.entries();
|
||||
while(entries.hasMoreElements()) {
|
||||
JarEntry entry = entries.nextElement();
|
||||
String name = entry.getName();
|
||||
if(!entry.isDirectory() && name.startsWith("LIB-INF") && name.endsWith(".jar")) {
|
||||
jarList.add(currentJarFile.getNestedJarFile(entry));
|
||||
}
|
||||
}
|
||||
ModuleLayer bootLayer = ModuleLayer.boot();
|
||||
Configuration bootConfiguration = bootLayer.configuration();
|
||||
Configuration cfg = bootConfiguration.resolve(new JarFileModuleFinder(jarList), ModuleFinder.of(), Collections.singletonList(mainModuleName));
|
||||
Map<String, ClassLoader> packageMap = new TreeMap<>();
|
||||
ModuleLayer.Controller controller =
|
||||
ModuleLayer.defineModules(cfg, Collections.singletonList(ModuleLayer.boot()), moduleName -> {
|
||||
ModuleReference modRef = cfg.findModule(moduleName)
|
||||
.map(ResolvedModule::reference)
|
||||
.orElseThrow();
|
||||
ClassLoader cl = new ModuleClassLoader(
|
||||
Collections.unmodifiableMap(packageMap),
|
||||
modRef
|
||||
);
|
||||
for(String packageName : modRef.descriptor().packages()) {
|
||||
packageMap.put(packageName, cl);
|
||||
}
|
||||
return cl;
|
||||
});
|
||||
ModuleLayer layer = controller.layer();
|
||||
Module mainModule = layer.findModule(mainModuleName).orElseThrow(
|
||||
() -> new IllegalStateException(String.format("Main module '%s' not found", mainModuleName)));
|
||||
runner.accept(Optional.ofNullable(mainClassName)
|
||||
.or(() -> mainModule.getDescriptor().mainClass())
|
||||
.map(className -> Class.forName(mainModule, className))
|
||||
.orElseThrow(() -> new IllegalStateException(
|
||||
String.format("Unable to determine main class name for module '%s'", mainModule.getName()))));
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,44 +1,49 @@
|
||||
package net.woggioni.envelope;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import net.woggioni.xclassloader.PathURLStreamHandler;
|
||||
import net.woggioni.xclassloader.URLManager;
|
||||
import net.woggioni.xclassloader.jar.JarFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.stream.Collector;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import static java.util.jar.JarFile.MANIFEST_NAME;
|
||||
|
||||
public class Launcher {
|
||||
|
||||
@SneakyThrows
|
||||
private static URI findCurrentJar() {
|
||||
private static JarFile findCurrentJar() {
|
||||
String launcherClassName = Launcher.class.getName();
|
||||
URL url = Launcher.class.getClassLoader().getResource(launcherClassName.replace('.', '/') + ".class");
|
||||
if (url == null || !"jar".equals(url.getProtocol()))
|
||||
throw new IllegalStateException(String.format("The class %s must be used inside a JAR file", launcherClassName));
|
||||
String path = url.getPath();
|
||||
return new URI(path.substring(0, path.indexOf('!')));
|
||||
String path = Paths.get(new URI(url.getPath())).toString();
|
||||
return new JarFile(new File(path.substring(0, path.indexOf('!'))));
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static void run(Class<?> mainClass, String[] args) {
|
||||
try {
|
||||
Method mainMethod = mainClass.getMethod("main", String[].class);
|
||||
Class<?> returnType = mainMethod.getReturnType();
|
||||
if (mainMethod.getReturnType() != Void.TYPE) {
|
||||
throw new IllegalArgumentException(String.format("Main method in class '%s' " +
|
||||
"has wrong return type, expected '%s', found '%s' instead", mainClass, Void.class.getName(), returnType));
|
||||
}
|
||||
mainMethod.invoke(null, (Object) args);
|
||||
} catch (NoSuchMethodException nsme) {
|
||||
throw new IllegalArgumentException(String.format("No valid main method found in class '%s'", mainClass), nsme);
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@@ -53,69 +58,58 @@ public class Launcher {
|
||||
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
|
||||
String key = (String) entry.getKey();
|
||||
String value = (String) entry.getValue();
|
||||
if(System.getProperty(key) == null) System.setProperty(key, value);
|
||||
if (System.getProperty(key) == null) System.setProperty(key, value);
|
||||
}
|
||||
}
|
||||
URI currentJar = findCurrentJar();
|
||||
String currentJarPath = currentJar.getPath();
|
||||
JarFile currentJar = findCurrentJar();
|
||||
URL manifestResource = null;
|
||||
Enumeration<URL> enumeration = Launcher.class.getClassLoader().getResources(JarFile.MANIFEST_NAME);
|
||||
while(enumeration.hasMoreElements()) {
|
||||
Enumeration<URL> enumeration = Launcher.class.getClassLoader().getResources(MANIFEST_NAME);
|
||||
while (enumeration.hasMoreElements()) {
|
||||
URL candidate = enumeration.nextElement();
|
||||
URL subUrl = new URL(candidate.getFile());
|
||||
String candidatePath = subUrl.getPath();
|
||||
int i = candidatePath.indexOf("!/");
|
||||
candidatePath = candidatePath.substring(0, i);
|
||||
if(Objects.equals(currentJarPath, candidatePath)) {
|
||||
if (Objects.equals(currentJar.getName(), candidatePath)) {
|
||||
manifestResource = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(Objects.isNull(manifestResource)) {
|
||||
if (Objects.isNull(manifestResource)) {
|
||||
throw new RuntimeException("Launcher manifest not found");
|
||||
}
|
||||
Manifest mf = new Manifest();
|
||||
try(InputStream is = manifestResource.openStream()) {
|
||||
try (InputStream is = manifestResource.openStream()) {
|
||||
mf.read(is);
|
||||
}
|
||||
try(FileSystem fs = FileSystems.newFileSystem(Paths.get(currentJar), null)) {
|
||||
Attributes mainAttributes = mf.getMainAttributes();
|
||||
Attributes mainAttributes = mf.getMainAttributes();
|
||||
|
||||
Collector<Path, ArrayList<Path>, List<Path>> immutableListCollector = Collector.of(
|
||||
ArrayList::new,
|
||||
List::add,
|
||||
(l1, l2) -> { l1.addAll(l2); return l1; },
|
||||
Collections::unmodifiableList);
|
||||
List<Path> jarList = StreamSupport.stream(fs.getRootDirectories().spliterator(), false).flatMap(new Function<Path, Stream<Path>>() {
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public Stream<Path> apply(Path path) {
|
||||
return Files.list(path.resolve(Constants.LIBRARIES_FOLDER))
|
||||
.filter(Files::isRegularFile)
|
||||
.filter(p -> p.getFileName().toString().endsWith(".jar"));
|
||||
}
|
||||
}).flatMap(new Function<Path, Stream<Path>>() {
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public Stream<Path> apply(Path path) {
|
||||
return StreamSupport.stream(FileSystems.newFileSystem(path, null).getRootDirectories().spliterator(), false);
|
||||
}
|
||||
}).collect(immutableListCollector);
|
||||
String mainClassName = mainAttributes.getValue(Constants.ManifestAttributes.MAIN_CLASS);
|
||||
String mainModuleName = mainAttributes.getValue(Constants.ManifestAttributes.MAIN_MODULE);
|
||||
|
||||
String mainClassName = mainAttributes.getValue(Constants.ManifestAttributes.MAIN_CLASS);
|
||||
String mainModuleName = mainAttributes.getValue(Constants.ManifestAttributes.MAIN_MODULE);
|
||||
Class<?> mainClass = MainClassLoader.loadMainClass(jarList, mainModuleName, mainClassName);
|
||||
try {
|
||||
Method mainMethod = mainClass.getMethod("main", String[].class);
|
||||
Class<?> returnType = mainMethod.getReturnType();
|
||||
if (mainMethod.getReturnType() != Void.TYPE) {
|
||||
throw new IllegalArgumentException(String.format("Main method in class '%s' " +
|
||||
"has wrong return type, expected '%s', found '%s' instead", mainClass, Void.class.getName(), returnType));
|
||||
Consumer<Class<?>> runner = new Consumer<Class<?>>() {
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public void accept(Class<?> mainClass) {
|
||||
try {
|
||||
Method mainMethod = mainClass.getMethod("main", String[].class);
|
||||
Class<?> returnType = mainMethod.getReturnType();
|
||||
if (mainMethod.getReturnType() != Void.TYPE) {
|
||||
throw new IllegalArgumentException(String.format("Main method in class '%s' " +
|
||||
"has wrong return type, expected '%s', found '%s' instead", mainClass, Void.class.getName(), returnType));
|
||||
}
|
||||
mainMethod.invoke(null, (Object) args);
|
||||
} catch (NoSuchMethodException nsme) {
|
||||
throw new IllegalArgumentException(String.format("No valid main method found in class '%s'", mainClass), nsme);
|
||||
}
|
||||
mainMethod.invoke(null, (Object) args);
|
||||
} catch (NoSuchMethodException nsme) {
|
||||
throw new IllegalArgumentException(String.format("No valid main method found in class '%s'", mainClass), nsme);
|
||||
}
|
||||
}
|
||||
};
|
||||
MainRunner.run(
|
||||
currentJar,
|
||||
mainModuleName,
|
||||
mainClassName,
|
||||
Constants.LIBRARIES_FOLDER,
|
||||
runner);
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -1,13 +0,0 @@
|
||||
package net.woggioni.envelope;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
class MainClassLoader {
|
||||
@SneakyThrows
|
||||
static Class<?> loadMainClass(Iterable<Path> roots, String mainModuleName, String mainClassName) {
|
||||
ClassLoader pathClassLoader = new net.woggioni.xclassloader.PathClassLoader(roots, ClassLoader.getSystemClassLoader().getParent());
|
||||
Thread.currentThread().setContextClassLoader(pathClassLoader);
|
||||
return pathClassLoader.loadClass(mainClassName);
|
||||
}
|
||||
}
|
35
launcher/src/main/java/net/woggioni/envelope/MainRunner.java
Normal file
35
launcher/src/main/java/net/woggioni/envelope/MainRunner.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package net.woggioni.envelope;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import net.woggioni.xclassloader.jar.JarFile;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.jar.JarEntry;
|
||||
|
||||
class MainRunner {
|
||||
@SneakyThrows
|
||||
static void run(JarFile currentJarFile,
|
||||
String mainModuleName,
|
||||
String mainClassName,
|
||||
String librariesFolder,
|
||||
Consumer<Class<?>> runner) {
|
||||
List<URL> jarList = new ArrayList<>();
|
||||
Enumeration<JarEntry> entries = currentJarFile.entries();
|
||||
while(entries.hasMoreElements()) {
|
||||
JarEntry entry = entries.nextElement();
|
||||
String name = entry.getName();
|
||||
if(!entry.isDirectory() && name.startsWith(librariesFolder) && name.endsWith(".jar")) {
|
||||
jarList.add(currentJarFile.getNestedJarFile(entry).getUrl());
|
||||
}
|
||||
}
|
||||
try (URLClassLoader cl = new URLClassLoader(jarList.toArray(new URL[0]), ClassLoader.getSystemClassLoader().getParent())) {
|
||||
Thread.currentThread().setContextClassLoader(cl);
|
||||
runner.accept(cl.loadClass(mainClassName));
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,55 +0,0 @@
|
||||
package net.woggioni.envelope;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.lang.module.Configuration;
|
||||
import java.lang.module.ModuleFinder;
|
||||
import java.lang.module.ResolvedModule;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import net.woggioni.xclassloader.PathClassLoader;
|
||||
import net.woggioni.xclassloader.ModuleClassLoader;
|
||||
import net.woggioni.xclassloader.PathModuleFinder;
|
||||
|
||||
class MainClassLoader {
|
||||
|
||||
@SneakyThrows
|
||||
static Class<?> loadMainClass(Iterable<Path> roots, String mainModuleName, String mainClassName) {
|
||||
if (mainModuleName == null) {
|
||||
ClassLoader pathClassLoader = new net.woggioni.xclassloader.PathClassLoader(roots, ClassLoader.getSystemClassLoader().getParent());
|
||||
Thread.currentThread().setContextClassLoader(pathClassLoader);
|
||||
return pathClassLoader.loadClass(mainClassName);
|
||||
} else {
|
||||
ModuleLayer bootLayer = ModuleLayer.boot();
|
||||
Configuration bootConfiguration = bootLayer.configuration();
|
||||
Configuration cfg = bootConfiguration.resolve(new PathModuleFinder(roots), ModuleFinder.of(), Collections.singletonList(mainModuleName));
|
||||
Map<String, ClassLoader> packageMap = new TreeMap<>();
|
||||
ModuleLayer.Controller controller =
|
||||
ModuleLayer.defineModules(cfg, Collections.singletonList(ModuleLayer.boot()), moduleName -> {
|
||||
ModuleReference modRef = cfg.findModule(moduleName)
|
||||
.map(ResolvedModule::reference)
|
||||
.orElseThrow();
|
||||
ClassLoader cl = new ModuleClassLoader(
|
||||
Collections.unmodifiableMap(packageMap),
|
||||
modRef
|
||||
);
|
||||
for(String packageName : modRef.descriptor().packages()) {
|
||||
packageMap.put(packageName, cl);
|
||||
}
|
||||
return cl;
|
||||
});
|
||||
ModuleLayer layer = controller.layer();
|
||||
Module mainModule = layer.findModule(mainModuleName).orElseThrow(
|
||||
() -> new IllegalStateException(String.format("Main module '%s' not found", mainModuleName)));
|
||||
return Optional.ofNullable(mainClassName)
|
||||
.or(() -> mainModule.getDescriptor().mainClass())
|
||||
.map(className -> Class.forName(mainModule, className))
|
||||
.orElseThrow(() -> new IllegalStateException(String.format("Unable to determine main class name for module '%s'", mainModule.getName())));
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,86 @@
|
||||
package net.woggioni.envelope;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.lang.module.Configuration;
|
||||
import java.lang.module.ModuleFinder;
|
||||
import java.lang.module.ResolvedModule;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Optional;
|
||||
import java.util.Enumeration;
|
||||
import java.util.function.Consumer;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import net.woggioni.xclassloader.ModuleClassLoader;
|
||||
import net.woggioni.xclassloader.JarFileModuleFinder;
|
||||
import net.woggioni.xclassloader.jar.JarFile;
|
||||
import java.util.jar.JarEntry;
|
||||
|
||||
class MainRunner {
|
||||
|
||||
@SneakyThrows
|
||||
static void run(JarFile currentJarFile,
|
||||
String mainModuleName,
|
||||
String mainClassName,
|
||||
String librariesFolder,
|
||||
Consumer<Class<?>> runner) {
|
||||
if(mainModuleName == null) {
|
||||
List<URL> jarList = new ArrayList<>();
|
||||
Enumeration<JarEntry> entries = currentJarFile.entries();
|
||||
while(entries.hasMoreElements()) {
|
||||
JarEntry entry = entries.nextElement();
|
||||
String name = entry.getName();
|
||||
if(!entry.isDirectory() && name.startsWith(librariesFolder) && name.endsWith(".jar")) {
|
||||
jarList.add(currentJarFile.getNestedJarFile(entry).getUrl());
|
||||
}
|
||||
}
|
||||
try (URLClassLoader cl = new URLClassLoader(jarList.toArray(new URL[0]), ClassLoader.getSystemClassLoader().getParent())) {
|
||||
Thread.currentThread().setContextClassLoader(cl);
|
||||
runner.accept(cl.loadClass(mainClassName));
|
||||
}
|
||||
} else {
|
||||
List<JarFile> jarList = new ArrayList<>();
|
||||
Enumeration<JarEntry> entries = currentJarFile.entries();
|
||||
while(entries.hasMoreElements()) {
|
||||
JarEntry entry = entries.nextElement();
|
||||
String name = entry.getName();
|
||||
if(!entry.isDirectory() && name.startsWith("LIB-INF") && name.endsWith(".jar")) {
|
||||
jarList.add(currentJarFile.getNestedJarFile(entry));
|
||||
}
|
||||
}
|
||||
ModuleLayer bootLayer = ModuleLayer.boot();
|
||||
Configuration bootConfiguration = bootLayer.configuration();
|
||||
Configuration cfg = bootConfiguration.resolve(new JarFileModuleFinder(jarList), ModuleFinder.of(), Collections.singletonList(mainModuleName));
|
||||
Map<String, ClassLoader> packageMap = new TreeMap<>();
|
||||
ModuleLayer.Controller controller =
|
||||
ModuleLayer.defineModules(cfg, Collections.singletonList(ModuleLayer.boot()), moduleName -> {
|
||||
ModuleReference modRef = cfg.findModule(moduleName)
|
||||
.map(ResolvedModule::reference)
|
||||
.orElseThrow();
|
||||
ClassLoader cl = new ModuleClassLoader(
|
||||
Collections.unmodifiableMap(packageMap),
|
||||
modRef
|
||||
);
|
||||
for(String packageName : modRef.descriptor().packages()) {
|
||||
packageMap.put(packageName, cl);
|
||||
}
|
||||
return cl;
|
||||
});
|
||||
ModuleLayer layer = controller.layer();
|
||||
Module mainModule = layer.findModule(mainModuleName).orElseThrow(
|
||||
() -> new IllegalStateException(String.format("Main module '%s' not found", mainModuleName)));
|
||||
runner.accept(Optional.ofNullable(mainClassName)
|
||||
.or(() -> mainModule.getDescriptor().mainClass())
|
||||
.map(className -> Class.forName(mainModule, className))
|
||||
.orElseThrow(() -> new IllegalStateException(
|
||||
String.format("Unable to determine main class name for module '%s'", mainModule.getName()))));
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user