mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-12-22 08:31:07 +03:00
[REFACTOR] Using Java 17
This commit is contained in:
parent
0855fc589d
commit
dfbb6e507a
10 changed files with 324 additions and 634 deletions
|
@ -1,5 +1,5 @@
|
||||||
sourceCompatibility = '1.8'
|
sourceCompatibility = '17'
|
||||||
targetCompatibility = '1.8'
|
targetCompatibility = '17'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api project(':LauncherCore')
|
api project(':LauncherCore')
|
||||||
|
@ -14,29 +14,10 @@ api project(':LauncherCore')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
|
||||||
java11 {
|
|
||||||
java {
|
|
||||||
srcDirs = ['src/main/java11']
|
|
||||||
}
|
|
||||||
dependencies {
|
|
||||||
java11Implementation files(sourceSets.main.output.classesDirs) { builtBy compileJava }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
into('META-INF/versions/11') {
|
|
||||||
from sourceSets.java11.output
|
|
||||||
}
|
|
||||||
archiveClassifier.set('clean')
|
archiveClassifier.set('clean')
|
||||||
}
|
}
|
||||||
|
|
||||||
compileJava11Java {
|
|
||||||
sourceCompatibility = 11
|
|
||||||
targetCompatibility = 11
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register('sourcesJar', Jar) {
|
tasks.register('sourcesJar', Jar) {
|
||||||
from sourceSets.main.allJava
|
from sourceSets.main.allJava
|
||||||
archiveClassifier.set('sources')
|
archiveClassifier.set('sources')
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
url "https://repo.spring.io/plugins-release/"
|
url "https://repo.spring.io/plugins-release/"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sourceCompatibility = '1.8'
|
sourceCompatibility = '17'
|
||||||
targetCompatibility = '1.8'
|
targetCompatibility = '17'
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
archiveClassifier.set('clean')
|
archiveClassifier.set('clean')
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
sourceCompatibility = '1.8'
|
sourceCompatibility = '17'
|
||||||
targetCompatibility = '1.8'
|
targetCompatibility = '17'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly group: 'org.fusesource.jansi', name: 'jansi', version: rootProject['verJansi']
|
compileOnly group: 'org.fusesource.jansi', name: 'jansi', version: rootProject['verJansi']
|
||||||
|
@ -21,28 +21,10 @@
|
||||||
events "passed", "skipped", "failed"
|
events "passed", "skipped", "failed"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sourceSets {
|
|
||||||
java11 {
|
|
||||||
java {
|
|
||||||
srcDirs = ['src/main/java11']
|
|
||||||
}
|
|
||||||
dependencies {
|
|
||||||
java11Implementation group: 'com.google.code.gson', name: 'gson', version: rootProject['verGson']
|
|
||||||
java11Implementation files(sourceSets.main.output.classesDirs) { builtBy compileJava }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jar {
|
jar {
|
||||||
into('META-INF/versions/11') {
|
|
||||||
from sourceSets.java11.output
|
|
||||||
}
|
|
||||||
archiveClassifier.set('clean')
|
archiveClassifier.set('clean')
|
||||||
manifest.attributes("Multi-Release": "true")
|
manifest.attributes("Multi-Release": "true")
|
||||||
}
|
}
|
||||||
compileJava11Java {
|
|
||||||
sourceCompatibility = 11
|
|
||||||
targetCompatibility = 11
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register('sourcesJar', Jar) {
|
tasks.register('sourcesJar', Jar) {
|
||||||
from sourceSets.main.allJava
|
from sourceSets.main.allJava
|
||||||
|
|
|
@ -53,35 +53,12 @@ public static ARCH getArch(String arch) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getVersion() {
|
public static int getVersion() {
|
||||||
String version = System.getProperty("java.version");
|
//System.out.println("[DEBUG] JVMHelper 11 version");
|
||||||
if (version.startsWith("1.")) {
|
return Runtime.version().feature();
|
||||||
version = version.substring(2, 3);
|
|
||||||
} else {
|
|
||||||
int dot = version.indexOf(".");
|
|
||||||
if (dot != -1) {
|
|
||||||
version = version.substring(0, dot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Integer.parseInt(version);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getBuild() {
|
public static int getBuild() {
|
||||||
String version = System.getProperty("java.version");
|
return Runtime.version().update();
|
||||||
int dot;
|
|
||||||
if (version.startsWith("1.")) {
|
|
||||||
dot = version.indexOf("_");
|
|
||||||
} else {
|
|
||||||
dot = version.lastIndexOf(".");
|
|
||||||
}
|
|
||||||
if (dot != -1) {
|
|
||||||
version = version.substring(dot + 1);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return Integer.parseInt(version);
|
|
||||||
} catch (NumberFormatException exception) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getNativeExtension(JVMHelper.OS OS_TYPE) {
|
public static String getNativeExtension(JVMHelper.OS OS_TYPE) {
|
||||||
|
|
|
@ -1,17 +1,323 @@
|
||||||
package pro.gravit.utils.launch;
|
package pro.gravit.utils.launch;
|
||||||
|
|
||||||
|
import pro.gravit.utils.helper.HackHelper;
|
||||||
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
|
import pro.gravit.utils.helper.JVMHelper;
|
||||||
|
import pro.gravit.utils.helper.LogHelper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.lang.invoke.MethodHandle;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.MethodType;
|
||||||
|
import java.lang.module.Configuration;
|
||||||
|
import java.lang.module.ModuleFinder;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLClassLoader;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Collection;
|
import java.nio.file.Paths;
|
||||||
import java.util.List;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class ModuleLaunch implements Launch {
|
public class ModuleLaunch implements Launch {
|
||||||
|
private ModuleClassLoader moduleClassLoader;
|
||||||
|
private Configuration configuration;
|
||||||
|
private ModuleLayer.Controller controller;
|
||||||
|
private ModuleFinder moduleFinder;
|
||||||
|
private ModuleLayer layer;
|
||||||
|
private MethodHandles.Lookup hackLookup;
|
||||||
|
private boolean disablePackageDelegateSupport;
|
||||||
@Override
|
@Override
|
||||||
public ClassLoaderControl init(List<Path> files, String nativePath, LaunchOptions options) {
|
public ClassLoaderControl init(List<Path> files, String nativePath, LaunchOptions options) {
|
||||||
throw new UnsupportedOperationException("Please use Multi-Release JAR");
|
this.disablePackageDelegateSupport = options.disablePackageDelegateSupport;
|
||||||
|
moduleClassLoader = new ModuleClassLoader(files.stream().map((e) -> {
|
||||||
|
try {
|
||||||
|
return e.toUri().toURL();
|
||||||
|
} catch (MalformedURLException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}).toArray(URL[]::new), ClassLoader.getPlatformClassLoader());
|
||||||
|
moduleClassLoader.nativePath = nativePath;
|
||||||
|
{
|
||||||
|
if(options.enableHacks) {
|
||||||
|
hackLookup = HackHelper.createHackLookup(ModuleLaunch.class);
|
||||||
|
}
|
||||||
|
if(options.moduleConf != null) {
|
||||||
|
// Create Module Layer
|
||||||
|
moduleFinder = ModuleFinder.of(options.moduleConf.modulePath.stream().map(Paths::get).map(Path::toAbsolutePath).toArray(Path[]::new));
|
||||||
|
ModuleLayer bootLayer = ModuleLayer.boot();
|
||||||
|
if(options.moduleConf.modules.contains("ALL-MODULE-PATH")) {
|
||||||
|
var set = moduleFinder.findAll();
|
||||||
|
if(LogHelper.isDevEnabled()) {
|
||||||
|
for(var m : set) {
|
||||||
|
LogHelper.dev("Found module %s in %s", m.descriptor().name(), m.location().map(URI::toString).orElse("unknown"));
|
||||||
|
}
|
||||||
|
LogHelper.dev("Found %d modules", set.size());
|
||||||
|
}
|
||||||
|
for(var m : set) {
|
||||||
|
options.moduleConf.modules.add(m.descriptor().name());
|
||||||
|
}
|
||||||
|
options.moduleConf.modules.remove("ALL-MODULE-PATH");
|
||||||
|
}
|
||||||
|
configuration = bootLayer.configuration()
|
||||||
|
.resolveAndBind(moduleFinder, ModuleFinder.of(), options.moduleConf.modules);
|
||||||
|
controller = ModuleLayer.defineModulesWithOneLoader(configuration, List.of(bootLayer), moduleClassLoader);
|
||||||
|
layer = controller.layer();
|
||||||
|
// Configure exports / opens
|
||||||
|
for(var e : options.moduleConf.exports.entrySet()) {
|
||||||
|
String[] split = e.getKey().split("/");
|
||||||
|
String moduleName = split[0];
|
||||||
|
String pkg = split[1];
|
||||||
|
LogHelper.dev("Export module: %s package: %s to %s", moduleName, pkg, e.getValue());
|
||||||
|
Module source = layer.findModule(split[0]).orElse(null);
|
||||||
|
if(source == null) {
|
||||||
|
throw new RuntimeException(String.format("Module %s not found", moduleName));
|
||||||
|
}
|
||||||
|
Module target = layer.findModule(e.getValue()).orElse(null);
|
||||||
|
if(target == null) {
|
||||||
|
throw new RuntimeException(String.format("Module %s not found", e.getValue()));
|
||||||
|
}
|
||||||
|
if(options.enableHacks && source.getLayer() != layer) {
|
||||||
|
ModuleHacks.createController(hackLookup, source.getLayer()).addExports(source, pkg, target);
|
||||||
|
} else {
|
||||||
|
controller.addExports(source, pkg, target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(var e : options.moduleConf.opens.entrySet()) {
|
||||||
|
String[] split = e.getKey().split("/");
|
||||||
|
String moduleName = split[0];
|
||||||
|
String pkg = split[1];
|
||||||
|
LogHelper.dev("Open module: %s package: %s to %s", moduleName, pkg, e.getValue());
|
||||||
|
Module source = layer.findModule(split[0]).orElse(null);
|
||||||
|
if(source == null) {
|
||||||
|
throw new RuntimeException(String.format("Module %s not found", moduleName));
|
||||||
|
}
|
||||||
|
Module target = layer.findModule(e.getValue()).orElse(null);
|
||||||
|
if(target == null) {
|
||||||
|
throw new RuntimeException(String.format("Module %s not found", e.getValue()));
|
||||||
|
}
|
||||||
|
if(options.enableHacks && source.getLayer() != layer) {
|
||||||
|
ModuleHacks.createController(hackLookup, source.getLayer()).addOpens(source, pkg, target);
|
||||||
|
} else {
|
||||||
|
controller.addOpens(source, pkg, target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(var e : options.moduleConf.reads.entrySet()) {
|
||||||
|
LogHelper.dev("Read module %s to %s", e.getKey(), e.getValue());
|
||||||
|
Module source = layer.findModule(e.getKey()).orElse(null);
|
||||||
|
if(source == null) {
|
||||||
|
throw new RuntimeException(String.format("Module %s not found", e.getKey()));
|
||||||
|
}
|
||||||
|
Module target = layer.findModule(e.getValue()).orElse(null);
|
||||||
|
if(target == null) {
|
||||||
|
throw new RuntimeException(String.format("Module %s not found", e.getValue()));
|
||||||
|
}
|
||||||
|
if(options.enableHacks && source.getLayer() != layer) {
|
||||||
|
ModuleHacks.createController(hackLookup, source.getLayer()).addReads(source, target);
|
||||||
|
} else {
|
||||||
|
controller.addReads(source, target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
moduleClassLoader.initializeWithLayer(layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return moduleClassLoader.makeControl();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void launch(String mainClass, String mainModule, Collection<String> args) throws Throwable {
|
public void launch(String mainClass, String mainModuleName, Collection<String> args) throws Throwable {
|
||||||
throw new UnsupportedOperationException("Please use Multi-Release JAR");
|
Thread.currentThread().setContextClassLoader(moduleClassLoader);
|
||||||
|
if(mainModuleName == null) {
|
||||||
|
Class<?> mainClazz = Class.forName(mainClass, true, moduleClassLoader);
|
||||||
|
MethodHandle mainMethod = MethodHandles.lookup().findStatic(mainClazz, "main", MethodType.methodType(void.class, String[].class)).asFixedArity();
|
||||||
|
JVMHelper.fullGC();
|
||||||
|
mainMethod.asFixedArity().invokeWithArguments((Object) args.toArray(new String[0]));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Module mainModule = layer.findModule(mainModuleName).orElseThrow();
|
||||||
|
Module unnamed = ModuleLaunch.class.getClassLoader().getUnnamedModule();
|
||||||
|
if(unnamed != null) {
|
||||||
|
controller.addOpens(mainModule, getPackageFromClass(mainClass), unnamed);
|
||||||
|
}
|
||||||
|
// Start main class
|
||||||
|
ClassLoader loader = mainModule.getClassLoader();
|
||||||
|
Class<?> mainClazz = Class.forName(mainClass, true, loader);
|
||||||
|
MethodHandle mainMethod = MethodHandles.lookup().findStatic(mainClazz, "main", MethodType.methodType(void.class, String[].class));
|
||||||
|
mainMethod.asFixedArity().invokeWithArguments((Object) args.toArray(new String[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getPackageFromClass(String clazz) {
|
||||||
|
int index = clazz.lastIndexOf(".");
|
||||||
|
if(index >= 0) {
|
||||||
|
return clazz.substring(0, index);
|
||||||
|
}
|
||||||
|
return clazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ModuleClassLoader extends URLClassLoader {
|
||||||
|
private final ClassLoader SYSTEM_CLASS_LOADER = ClassLoader.getSystemClassLoader();
|
||||||
|
private final List<ClassLoaderControl.ClassTransformer> transformers = new ArrayList<>();
|
||||||
|
private final Map<String, Class<?>> classMap = new ConcurrentHashMap<>();
|
||||||
|
private final Map<String, Module> packageToModule = new HashMap<>();
|
||||||
|
private String nativePath;
|
||||||
|
|
||||||
|
private final List<String> packages = new ArrayList<>();
|
||||||
|
public ModuleClassLoader(URL[] urls, ClassLoader parent) {
|
||||||
|
super("LAUNCHER", urls, parent);
|
||||||
|
packages.add("pro.gravit.launcher.");
|
||||||
|
packages.add("pro.gravit.utils.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeWithLayer(ModuleLayer layer) {
|
||||||
|
for(var m : layer.modules()) {
|
||||||
|
for(var p : m.getPackages()) {
|
||||||
|
packageToModule.put(p, m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
||||||
|
if(name != null && !disablePackageDelegateSupport) {
|
||||||
|
for(String pkg : packages) {
|
||||||
|
if(name.startsWith(pkg)) {
|
||||||
|
return SYSTEM_CLASS_LOADER.loadClass(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.loadClass(name, resolve);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||||
|
var clazz = findClass(null, name);
|
||||||
|
if(clazz == null) {
|
||||||
|
throw new ClassNotFoundException(name);
|
||||||
|
}
|
||||||
|
return clazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?> findClass(String moduleName, String name) {
|
||||||
|
Class<?> clazz;
|
||||||
|
{
|
||||||
|
clazz = classMap.get(name);
|
||||||
|
if(clazz != null) {
|
||||||
|
return clazz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(name != null && !transformers.isEmpty()) {
|
||||||
|
boolean needTransform = false;
|
||||||
|
for(ClassLoaderControl.ClassTransformer t : transformers) {
|
||||||
|
if(t.filter(moduleName, name)) {
|
||||||
|
needTransform = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(needTransform) {
|
||||||
|
String rawClassName = name.replace(".", "/").concat(".class");
|
||||||
|
try(InputStream input = getResourceAsStream(rawClassName)) {
|
||||||
|
byte[] bytes = IOHelper.read(input);
|
||||||
|
for(ClassLoaderControl.ClassTransformer t : transformers) {
|
||||||
|
bytes = t.transform(moduleName, name, null, bytes);
|
||||||
|
}
|
||||||
|
clazz = defineClass(name, bytes, 0, bytes.length);
|
||||||
|
} catch (IOException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(clazz == null && layer != null && name != null) {
|
||||||
|
var pkg = getPackageFromClass(name);
|
||||||
|
var module = packageToModule.get(pkg);
|
||||||
|
if(module != null) {
|
||||||
|
try {
|
||||||
|
clazz = module.getClassLoader().loadClass(name);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(clazz == null) {
|
||||||
|
try {
|
||||||
|
clazz = super.findClass(name);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(clazz != null) {
|
||||||
|
classMap.put(name, clazz);
|
||||||
|
return clazz;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String findLibrary(String name) {
|
||||||
|
return nativePath.concat(IOHelper.PLATFORM_SEPARATOR).concat(JVMHelper.NATIVE_PREFIX).concat(name).concat(JVMHelper.NATIVE_EXTENSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addAllowedPackage(String pkg) {
|
||||||
|
packages.add(pkg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ModuleClassLoaderControl makeControl() {
|
||||||
|
return new ModuleClassLoaderControl();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ModuleClassLoaderControl implements ClassLoaderControl {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addLauncherPackage(String prefix) {
|
||||||
|
addAllowedPackage(prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addTransformer(ClassTransformer transformer) {
|
||||||
|
transformers.add(transformer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addURL(URL url) {
|
||||||
|
ModuleClassLoader.this.addURL(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addJar(Path path) {
|
||||||
|
try {
|
||||||
|
ModuleClassLoader.this.addURL(path.toUri().toURL());
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URL[] getURLs() {
|
||||||
|
return ModuleClassLoader.this.getURLs();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> getClass(String name) throws ClassNotFoundException {
|
||||||
|
return Class.forName(name, false, ModuleClassLoader.this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClassLoader getClassLoader() {
|
||||||
|
return ModuleClassLoader.this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getJava9ModuleController() {
|
||||||
|
return controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MethodHandles.Lookup getHackLookup() {
|
||||||
|
return hackLookup;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,213 +0,0 @@
|
||||||
package pro.gravit.utils.helper;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.lang.invoke.MethodHandles;
|
|
||||||
import java.lang.management.ManagementFactory;
|
|
||||||
import java.lang.management.OperatingSystemMXBean;
|
|
||||||
import java.lang.management.RuntimeMXBean;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public final class JVMHelper {
|
|
||||||
|
|
||||||
// MXBeans exports
|
|
||||||
public static final RuntimeMXBean RUNTIME_MXBEAN = ManagementFactory.getRuntimeMXBean();
|
|
||||||
public static final OperatingSystemMXBean OPERATING_SYSTEM_MXBEAN =
|
|
||||||
ManagementFactory.getOperatingSystemMXBean();
|
|
||||||
public static final OS OS_TYPE = OS.byName(OPERATING_SYSTEM_MXBEAN.getName());
|
|
||||||
public static final int OS_BITS = getCorrectOSArch();
|
|
||||||
// System properties
|
|
||||||
public static final String OS_VERSION = OPERATING_SYSTEM_MXBEAN.getVersion();
|
|
||||||
public static final ARCH ARCH_TYPE = getArch(System.getProperty("os.arch"));
|
|
||||||
public static final String NATIVE_EXTENSION = getNativeExtension(OS_TYPE);
|
|
||||||
public static final String NATIVE_PREFIX = getNativePrefix(OS_TYPE);
|
|
||||||
public static final int JVM_BITS = Integer.parseInt(System.getProperty("sun.arch.data.model"));
|
|
||||||
// Public static fields
|
|
||||||
public static final Runtime RUNTIME = Runtime.getRuntime();
|
|
||||||
public static final ClassLoader LOADER = ClassLoader.getSystemClassLoader();
|
|
||||||
public static final int JVM_VERSION = getVersion();
|
|
||||||
public static final int JVM_BUILD = getBuild();
|
|
||||||
|
|
||||||
static {
|
|
||||||
try {
|
|
||||||
MethodHandles.publicLookup(); // Just to initialize class
|
|
||||||
} catch (Throwable exc) {
|
|
||||||
throw new InternalError(exc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private JVMHelper() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ARCH getArch(String arch) {
|
|
||||||
if (arch.equals("amd64") || arch.equals("x86-64") || arch.equals("x86_64")) return ARCH.X86_64;
|
|
||||||
if (arch.equals("i386") || arch.equals("i686") || arch.equals("x86")) return ARCH.X86;
|
|
||||||
if (arch.startsWith("armv8") || arch.startsWith("aarch64")) return ARCH.ARM64;
|
|
||||||
if (arch.startsWith("arm") || arch.startsWith("aarch32")) return ARCH.ARM32;
|
|
||||||
throw new InternalError(String.format("Unsupported arch '%s'", arch));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getVersion() {
|
|
||||||
//System.out.println("[DEBUG] JVMHelper 11 version");
|
|
||||||
return Runtime.version().feature();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getBuild() {
|
|
||||||
return Runtime.version().update();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getNativeExtension(JVMHelper.OS OS_TYPE) {
|
|
||||||
switch (OS_TYPE) {
|
|
||||||
case MUSTDIE:
|
|
||||||
return ".dll";
|
|
||||||
case LINUX:
|
|
||||||
return ".so";
|
|
||||||
case MACOSX:
|
|
||||||
return ".dylib";
|
|
||||||
default:
|
|
||||||
throw new InternalError(String.format("Unsupported OS TYPE '%s'", OS_TYPE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getNativePrefix(JVMHelper.OS OS_TYPE) {
|
|
||||||
switch (OS_TYPE) {
|
|
||||||
case LINUX:
|
|
||||||
case MACOSX:
|
|
||||||
return "lib";
|
|
||||||
default:
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void appendVars(ProcessBuilder builder, Map<String, String> vars) {
|
|
||||||
builder.environment().putAll(vars);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Class<?> firstClass(String... names) throws ClassNotFoundException {
|
|
||||||
for (String name : names)
|
|
||||||
try {
|
|
||||||
return Class.forName(name, false, LOADER);
|
|
||||||
} catch (ClassNotFoundException ignored) {
|
|
||||||
// Expected
|
|
||||||
}
|
|
||||||
throw new ClassNotFoundException(Arrays.toString(names));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void fullGC() {
|
|
||||||
RUNTIME.gc();
|
|
||||||
LogHelper.debug("Used heap: %d MiB", RUNTIME.totalMemory() - RUNTIME.freeMemory() >> 20);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String[] getClassPath() {
|
|
||||||
return System.getProperty("java.class.path").split(File.pathSeparator);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static URL[] getClassPathURL() {
|
|
||||||
String[] cp = System.getProperty("java.class.path").split(File.pathSeparator);
|
|
||||||
URL[] list = new URL[cp.length];
|
|
||||||
|
|
||||||
for (int i = 0; i < cp.length; i++) {
|
|
||||||
URL url = null;
|
|
||||||
try {
|
|
||||||
url = new URL(cp[i]);
|
|
||||||
} catch (MalformedURLException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
list[i] = url;
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static X509Certificate[] getCertificates(Class<?> clazz) {
|
|
||||||
Object[] signers = clazz.getSigners();
|
|
||||||
if (signers == null) return null;
|
|
||||||
return Arrays.stream(signers).filter((c) -> c instanceof X509Certificate).map((c) -> (X509Certificate) c).toArray(X509Certificate[]::new);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void checkStackTrace(Class<?> mainClass) {
|
|
||||||
LogHelper.debug("Testing stacktrace");
|
|
||||||
Exception e = new Exception("Testing stacktrace");
|
|
||||||
StackTraceElement[] list = e.getStackTrace();
|
|
||||||
if (!list[list.length - 1].getClassName().equals(mainClass.getName())) {
|
|
||||||
throw new SecurityException(String.format("Invalid StackTraceElement: %s", list[list.length - 1].getClassName()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int getCorrectOSArch() {
|
|
||||||
// As always, mustdie must die
|
|
||||||
if (OS_TYPE == OS.MUSTDIE)
|
|
||||||
return System.getenv("ProgramFiles(x86)") == null ? 32 : 64;
|
|
||||||
|
|
||||||
// Or trust system property (maybe incorrect)
|
|
||||||
return System.getProperty("os.arch").contains("64") ? 64 : 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getEnvPropertyCaseSensitive(String name) {
|
|
||||||
return System.getenv().get(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isJVMMatchesSystemArch() {
|
|
||||||
return JVM_BITS == OS_BITS;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String jvmProperty(String name, String value) {
|
|
||||||
return String.format("-D%s=%s", name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String systemToJvmProperty(String name) {
|
|
||||||
return String.format("-D%s=%s", name, System.getProperties().getProperty(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addSystemPropertyToArgs(Collection<String> args, String name) {
|
|
||||||
String property = System.getProperty(name);
|
|
||||||
if (property != null)
|
|
||||||
args.add(String.format("-D%s=%s", name, property));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void verifySystemProperties(Class<?> mainClass, boolean requireSystem) {
|
|
||||||
Locale.setDefault(Locale.US);
|
|
||||||
// Verify class loader
|
|
||||||
LogHelper.debug("Verifying class loader");
|
|
||||||
if (requireSystem && !mainClass.getClassLoader().equals(LOADER))
|
|
||||||
throw new SecurityException("ClassLoader should be system");
|
|
||||||
|
|
||||||
// Verify system and java architecture
|
|
||||||
LogHelper.debug("Verifying JVM architecture");
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum ARCH {
|
|
||||||
X86("x86"), X86_64("x86-64"), ARM64("arm64"), ARM32("arm32");
|
|
||||||
|
|
||||||
public final String name;
|
|
||||||
|
|
||||||
ARCH(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum OS {
|
|
||||||
MUSTDIE("mustdie"), LINUX("linux"), MACOSX("macosx");
|
|
||||||
|
|
||||||
public final String name;
|
|
||||||
|
|
||||||
OS(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static OS byName(String name) {
|
|
||||||
if (name.startsWith("Windows"))
|
|
||||||
return MUSTDIE;
|
|
||||||
if (name.startsWith("Linux"))
|
|
||||||
return LINUX;
|
|
||||||
if (name.startsWith("Mac OS X"))
|
|
||||||
return MACOSX;
|
|
||||||
throw new RuntimeException(String.format("This shit is not yet supported: '%s'", name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,323 +0,0 @@
|
||||||
package pro.gravit.utils.launch;
|
|
||||||
|
|
||||||
import pro.gravit.utils.helper.HackHelper;
|
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
|
||||||
import pro.gravit.utils.helper.JVMHelper;
|
|
||||||
import pro.gravit.utils.helper.LogHelper;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.lang.invoke.MethodHandle;
|
|
||||||
import java.lang.invoke.MethodHandles;
|
|
||||||
import java.lang.invoke.MethodType;
|
|
||||||
import java.lang.module.Configuration;
|
|
||||||
import java.lang.module.ModuleFinder;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLClassLoader;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
public class ModuleLaunch implements Launch {
|
|
||||||
private ModuleClassLoader moduleClassLoader;
|
|
||||||
private Configuration configuration;
|
|
||||||
private ModuleLayer.Controller controller;
|
|
||||||
private ModuleFinder moduleFinder;
|
|
||||||
private ModuleLayer layer;
|
|
||||||
private MethodHandles.Lookup hackLookup;
|
|
||||||
private boolean disablePackageDelegateSupport;
|
|
||||||
@Override
|
|
||||||
public ClassLoaderControl init(List<Path> files, String nativePath, LaunchOptions options) {
|
|
||||||
this.disablePackageDelegateSupport = options.disablePackageDelegateSupport;
|
|
||||||
moduleClassLoader = new ModuleClassLoader(files.stream().map((e) -> {
|
|
||||||
try {
|
|
||||||
return e.toUri().toURL();
|
|
||||||
} catch (MalformedURLException ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
|
||||||
}).toArray(URL[]::new), ClassLoader.getPlatformClassLoader());
|
|
||||||
moduleClassLoader.nativePath = nativePath;
|
|
||||||
{
|
|
||||||
if(options.enableHacks) {
|
|
||||||
hackLookup = HackHelper.createHackLookup(ModuleLaunch.class);
|
|
||||||
}
|
|
||||||
if(options.moduleConf != null) {
|
|
||||||
// Create Module Layer
|
|
||||||
moduleFinder = ModuleFinder.of(options.moduleConf.modulePath.stream().map(Paths::get).map(Path::toAbsolutePath).toArray(Path[]::new));
|
|
||||||
ModuleLayer bootLayer = ModuleLayer.boot();
|
|
||||||
if(options.moduleConf.modules.contains("ALL-MODULE-PATH")) {
|
|
||||||
var set = moduleFinder.findAll();
|
|
||||||
if(LogHelper.isDevEnabled()) {
|
|
||||||
for(var m : set) {
|
|
||||||
LogHelper.dev("Found module %s in %s", m.descriptor().name(), m.location().map(URI::toString).orElse("unknown"));
|
|
||||||
}
|
|
||||||
LogHelper.dev("Found %d modules", set.size());
|
|
||||||
}
|
|
||||||
for(var m : set) {
|
|
||||||
options.moduleConf.modules.add(m.descriptor().name());
|
|
||||||
}
|
|
||||||
options.moduleConf.modules.remove("ALL-MODULE-PATH");
|
|
||||||
}
|
|
||||||
configuration = bootLayer.configuration()
|
|
||||||
.resolveAndBind(moduleFinder, ModuleFinder.of(), options.moduleConf.modules);
|
|
||||||
controller = ModuleLayer.defineModulesWithOneLoader(configuration, List.of(bootLayer), moduleClassLoader);
|
|
||||||
layer = controller.layer();
|
|
||||||
// Configure exports / opens
|
|
||||||
for(var e : options.moduleConf.exports.entrySet()) {
|
|
||||||
String[] split = e.getKey().split("/");
|
|
||||||
String moduleName = split[0];
|
|
||||||
String pkg = split[1];
|
|
||||||
LogHelper.dev("Export module: %s package: %s to %s", moduleName, pkg, e.getValue());
|
|
||||||
Module source = layer.findModule(split[0]).orElse(null);
|
|
||||||
if(source == null) {
|
|
||||||
throw new RuntimeException(String.format("Module %s not found", moduleName));
|
|
||||||
}
|
|
||||||
Module target = layer.findModule(e.getValue()).orElse(null);
|
|
||||||
if(target == null) {
|
|
||||||
throw new RuntimeException(String.format("Module %s not found", e.getValue()));
|
|
||||||
}
|
|
||||||
if(options.enableHacks && source.getLayer() != layer) {
|
|
||||||
ModuleHacks.createController(hackLookup, source.getLayer()).addExports(source, pkg, target);
|
|
||||||
} else {
|
|
||||||
controller.addExports(source, pkg, target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(var e : options.moduleConf.opens.entrySet()) {
|
|
||||||
String[] split = e.getKey().split("/");
|
|
||||||
String moduleName = split[0];
|
|
||||||
String pkg = split[1];
|
|
||||||
LogHelper.dev("Open module: %s package: %s to %s", moduleName, pkg, e.getValue());
|
|
||||||
Module source = layer.findModule(split[0]).orElse(null);
|
|
||||||
if(source == null) {
|
|
||||||
throw new RuntimeException(String.format("Module %s not found", moduleName));
|
|
||||||
}
|
|
||||||
Module target = layer.findModule(e.getValue()).orElse(null);
|
|
||||||
if(target == null) {
|
|
||||||
throw new RuntimeException(String.format("Module %s not found", e.getValue()));
|
|
||||||
}
|
|
||||||
if(options.enableHacks && source.getLayer() != layer) {
|
|
||||||
ModuleHacks.createController(hackLookup, source.getLayer()).addOpens(source, pkg, target);
|
|
||||||
} else {
|
|
||||||
controller.addOpens(source, pkg, target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(var e : options.moduleConf.reads.entrySet()) {
|
|
||||||
LogHelper.dev("Read module %s to %s", e.getKey(), e.getValue());
|
|
||||||
Module source = layer.findModule(e.getKey()).orElse(null);
|
|
||||||
if(source == null) {
|
|
||||||
throw new RuntimeException(String.format("Module %s not found", e.getKey()));
|
|
||||||
}
|
|
||||||
Module target = layer.findModule(e.getValue()).orElse(null);
|
|
||||||
if(target == null) {
|
|
||||||
throw new RuntimeException(String.format("Module %s not found", e.getValue()));
|
|
||||||
}
|
|
||||||
if(options.enableHacks && source.getLayer() != layer) {
|
|
||||||
ModuleHacks.createController(hackLookup, source.getLayer()).addReads(source, target);
|
|
||||||
} else {
|
|
||||||
controller.addReads(source, target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
moduleClassLoader.initializeWithLayer(layer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return moduleClassLoader.makeControl();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void launch(String mainClass, String mainModuleName, Collection<String> args) throws Throwable {
|
|
||||||
Thread.currentThread().setContextClassLoader(moduleClassLoader);
|
|
||||||
if(mainModuleName == null) {
|
|
||||||
Class<?> mainClazz = Class.forName(mainClass, true, moduleClassLoader);
|
|
||||||
MethodHandle mainMethod = MethodHandles.lookup().findStatic(mainClazz, "main", MethodType.methodType(void.class, String[].class)).asFixedArity();
|
|
||||||
JVMHelper.fullGC();
|
|
||||||
mainMethod.asFixedArity().invokeWithArguments((Object) args.toArray(new String[0]));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Module mainModule = layer.findModule(mainModuleName).orElseThrow();
|
|
||||||
Module unnamed = ModuleLaunch.class.getClassLoader().getUnnamedModule();
|
|
||||||
if(unnamed != null) {
|
|
||||||
controller.addOpens(mainModule, getPackageFromClass(mainClass), unnamed);
|
|
||||||
}
|
|
||||||
// Start main class
|
|
||||||
ClassLoader loader = mainModule.getClassLoader();
|
|
||||||
Class<?> mainClazz = Class.forName(mainClass, true, loader);
|
|
||||||
MethodHandle mainMethod = MethodHandles.lookup().findStatic(mainClazz, "main", MethodType.methodType(void.class, String[].class));
|
|
||||||
mainMethod.asFixedArity().invokeWithArguments((Object) args.toArray(new String[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getPackageFromClass(String clazz) {
|
|
||||||
int index = clazz.lastIndexOf(".");
|
|
||||||
if(index >= 0) {
|
|
||||||
return clazz.substring(0, index);
|
|
||||||
}
|
|
||||||
return clazz;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ModuleClassLoader extends URLClassLoader {
|
|
||||||
private final ClassLoader SYSTEM_CLASS_LOADER = ClassLoader.getSystemClassLoader();
|
|
||||||
private final List<ClassLoaderControl.ClassTransformer> transformers = new ArrayList<>();
|
|
||||||
private final Map<String, Class<?>> classMap = new ConcurrentHashMap<>();
|
|
||||||
private final Map<String, Module> packageToModule = new HashMap<>();
|
|
||||||
private String nativePath;
|
|
||||||
|
|
||||||
private final List<String> packages = new ArrayList<>();
|
|
||||||
public ModuleClassLoader(URL[] urls, ClassLoader parent) {
|
|
||||||
super("LAUNCHER", urls, parent);
|
|
||||||
packages.add("pro.gravit.launcher.");
|
|
||||||
packages.add("pro.gravit.utils.");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeWithLayer(ModuleLayer layer) {
|
|
||||||
for(var m : layer.modules()) {
|
|
||||||
for(var p : m.getPackages()) {
|
|
||||||
packageToModule.put(p, m);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
|
||||||
if(name != null && !disablePackageDelegateSupport) {
|
|
||||||
for(String pkg : packages) {
|
|
||||||
if(name.startsWith(pkg)) {
|
|
||||||
return SYSTEM_CLASS_LOADER.loadClass(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return super.loadClass(name, resolve);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
|
||||||
var clazz = findClass(null, name);
|
|
||||||
if(clazz == null) {
|
|
||||||
throw new ClassNotFoundException(name);
|
|
||||||
}
|
|
||||||
return clazz;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class<?> findClass(String moduleName, String name) {
|
|
||||||
Class<?> clazz;
|
|
||||||
{
|
|
||||||
clazz = classMap.get(name);
|
|
||||||
if(clazz != null) {
|
|
||||||
return clazz;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(name != null && !transformers.isEmpty()) {
|
|
||||||
boolean needTransform = false;
|
|
||||||
for(ClassLoaderControl.ClassTransformer t : transformers) {
|
|
||||||
if(t.filter(moduleName, name)) {
|
|
||||||
needTransform = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(needTransform) {
|
|
||||||
String rawClassName = name.replace(".", "/").concat(".class");
|
|
||||||
try(InputStream input = getResourceAsStream(rawClassName)) {
|
|
||||||
byte[] bytes = IOHelper.read(input);
|
|
||||||
for(ClassLoaderControl.ClassTransformer t : transformers) {
|
|
||||||
bytes = t.transform(moduleName, name, null, bytes);
|
|
||||||
}
|
|
||||||
clazz = defineClass(name, bytes, 0, bytes.length);
|
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(clazz == null && layer != null && name != null) {
|
|
||||||
var pkg = getPackageFromClass(name);
|
|
||||||
var module = packageToModule.get(pkg);
|
|
||||||
if(module != null) {
|
|
||||||
try {
|
|
||||||
clazz = module.getClassLoader().loadClass(name);
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(clazz == null) {
|
|
||||||
try {
|
|
||||||
clazz = super.findClass(name);
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(clazz != null) {
|
|
||||||
classMap.put(name, clazz);
|
|
||||||
return clazz;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String findLibrary(String name) {
|
|
||||||
return nativePath.concat(IOHelper.PLATFORM_SEPARATOR).concat(JVMHelper.NATIVE_PREFIX).concat(name).concat(JVMHelper.NATIVE_EXTENSION);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addAllowedPackage(String pkg) {
|
|
||||||
packages.add(pkg);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ModuleClassLoaderControl makeControl() {
|
|
||||||
return new ModuleClassLoaderControl();
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ModuleClassLoaderControl implements ClassLoaderControl {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addLauncherPackage(String prefix) {
|
|
||||||
addAllowedPackage(prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addTransformer(ClassTransformer transformer) {
|
|
||||||
transformers.add(transformer);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addURL(URL url) {
|
|
||||||
ModuleClassLoader.this.addURL(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addJar(Path path) {
|
|
||||||
try {
|
|
||||||
ModuleClassLoader.this.addURL(path.toUri().toURL());
|
|
||||||
} catch (MalformedURLException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public URL[] getURLs() {
|
|
||||||
return ModuleClassLoader.this.getURLs();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<?> getClass(String name) throws ClassNotFoundException {
|
|
||||||
return Class.forName(name, false, ModuleClassLoader.this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ClassLoader getClassLoader() {
|
|
||||||
return ModuleClassLoader.this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getJava9ModuleController() {
|
|
||||||
return controller;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MethodHandles.Lookup getHackLookup() {
|
|
||||||
return hackLookup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,8 +8,8 @@
|
||||||
url "https://repo.spring.io/plugins-release/"
|
url "https://repo.spring.io/plugins-release/"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sourceCompatibility = '1.8'
|
sourceCompatibility = '17'
|
||||||
targetCompatibility = '1.8'
|
targetCompatibility = '17'
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
archiveClassifier.set('clean')
|
archiveClassifier.set('clean')
|
||||||
|
|
|
@ -14,30 +14,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceCompatibility = '17'
|
||||||
java11 {
|
targetCompatibility = '17'
|
||||||
java {
|
|
||||||
srcDirs = ['src/main/java11']
|
|
||||||
}
|
|
||||||
dependencies {
|
|
||||||
java11Implementation project(':LauncherAPI')
|
|
||||||
java11Implementation files(sourceSets.main.output.classesDirs) { builtBy compileJava }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceCompatibility = '1.8'
|
|
||||||
targetCompatibility = '1.8'
|
|
||||||
|
|
||||||
compileJava11Java {
|
|
||||||
sourceCompatibility = 11
|
|
||||||
targetCompatibility = 11
|
|
||||||
}
|
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
into('META-INF/versions/11') {
|
|
||||||
from sourceSets.java11.output
|
|
||||||
}
|
|
||||||
archiveClassifier.set('clean')
|
archiveClassifier.set('clean')
|
||||||
manifest.attributes("Main-Class": mainClassName,
|
manifest.attributes("Main-Class": mainClassName,
|
||||||
"Premain-Class": mainAgentName,
|
"Premain-Class": mainAgentName,
|
||||||
|
|
Loading…
Reference in a new issue