Skip to content

Commit

Permalink
Support Java 21 main launch protocol in prod and dev mode
Browse files Browse the repository at this point in the history
Relates to: quarkusio#36154
  • Loading branch information
geoand committed Sep 26, 2023
1 parent f278b9b commit 22bf157
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import io.quarkus.bootstrap.app.RunningQuarkusApplication;
import io.quarkus.bootstrap.app.StartupAction;
import io.quarkus.bootstrap.classloading.QuarkusClassLoader;
import io.quarkus.bootstrap.runner.MainMethodInvoker;
import io.quarkus.builder.BuildResult;
import io.quarkus.deployment.builditem.ApplicationClassNameBuildItem;
import io.quarkus.deployment.builditem.DevServicesLauncherConfigResultBuildItem;
Expand Down Expand Up @@ -104,13 +105,12 @@ public RunningQuarkusApplication runMainClass(String... args) throws Exception {
try {
// force init here
Class<?> appClass = Class.forName(className, true, runtimeClassLoader);
Method start = appClass.getMethod("main", String[].class);
Thread t = new Thread(new Runnable() {
@Override
public void run() {
Thread.currentThread().setContextClassLoader(runtimeClassLoader);
try {
start.invoke(null, (Object) (args == null ? new String[0] : args));
MainMethodInvoker.invoke(appClass, args);
} catch (Throwable e) {
log.error("Error running Quarkus", e);
//this can happen if we did not make it to application init
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package io.quarkus.bootstrap.runner;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public final class MainMethodInvoker {

// follow the rules outlines in https://openjdk.org/jeps/445 section 'Selecting a main method'
public static void invoke(Class<?> mainClass, Object args)
throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException {

// public static void main(String[] args)
Method mainWithArgs = null;
try {
mainWithArgs = mainClass.getDeclaredMethod("main", String[].class);
int modifiers = mainWithArgs.getModifiers();
if (Modifier.isStatic(modifiers) && !Modifier.isPrivate(modifiers)) {
if (!Modifier.isPublic(modifiers)) {
mainWithArgs.setAccessible(true);
}
mainWithArgs.invoke(null, args);
return;
}
} catch (NoSuchMethodException ignored) {

}

// public static void main()
Method mainWithoutArgs = null;
try {
mainWithoutArgs = mainClass.getDeclaredMethod("main");
int modifiers = mainWithoutArgs.getModifiers();
if (Modifier.isStatic(modifiers) && !Modifier.isPrivate(modifiers)) {
if (!Modifier.isPublic(modifiers)) {
mainWithoutArgs.setAccessible(true);
}
mainWithoutArgs.invoke(null);
return;
}
} catch (NoSuchMethodException ignored) {

}

var instance = mainClass.getConstructor().newInstance();

// public void main(String[] args)
if (mainWithArgs != null) {
int modifiers = mainWithArgs.getModifiers();
if (!Modifier.isPrivate(modifiers)) {
if (!Modifier.isPublic(modifiers)) {
mainWithArgs.setAccessible(true);
}
mainWithArgs.invoke(instance, args);
return;
}
}

// public void main()
if (mainWithoutArgs != null) {
int modifiers = mainWithoutArgs.getModifiers();
if (!Modifier.isPrivate(modifiers)) {
if (!Modifier.isPublic(modifiers)) {
mainWithoutArgs.setAccessible(true);
}
mainWithoutArgs.invoke(instance);
return;
}
}

throw new NoSuchMethodException("Unable to find main method");
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.quarkus.bootstrap.runner;

import static io.quarkus.bootstrap.runner.MainMethodInvoker.invoke;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
Expand Down Expand Up @@ -36,7 +38,7 @@ public static void main(String... args) throws Throwable {
}
}

private static void doRun(Object args) throws IOException, ClassNotFoundException, IllegalAccessException,
private static void doRun(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException,
InvocationTargetException, NoSuchMethodException {
String path = QuarkusEntryPoint.class.getProtectionDomain().getCodeSource().getLocation().getPath();
String decodedPath = URLDecoder.decode(path, "UTF-8");
Expand All @@ -57,8 +59,12 @@ private static void doRun(Object args) throws IOException, ClassNotFoundExceptio
try {
Thread.currentThread().setContextClassLoader(appRunnerClassLoader);
QuarkusForkJoinWorkerThread.setQuarkusAppClassloader(appRunnerClassLoader);

Class<?> mainClass = appRunnerClassLoader.loadClass(app.getMainClass());
mainClass.getMethod("main", String[].class).invoke(null, args);

invoke(mainClass, args);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} finally {
QuarkusForkJoinWorkerThread.setQuarkusAppClassloader(null);
appRunnerClassLoader.close();
Expand Down

0 comments on commit 22bf157

Please sign in to comment.