fix runMain task. support JEP-512

This commit is contained in:
xuwei-k 2025-10-03 07:24:53 +09:00 committed by kenji yoshida
parent b536847ff0
commit 152fe61ced
9 changed files with 113 additions and 13 deletions

View File

@ -10,7 +10,7 @@ package sbt
import java.io.File import java.io.File
import java.lang.reflect.Method import java.lang.reflect.Method
import java.lang.reflect.Modifier.{ isPublic, isStatic } import java.lang.reflect.Modifier.{ isPrivate, isPublic, isStatic }
import sbt.internal.inc.ScalaInstance import sbt.internal.inc.ScalaInstance
import sbt.internal.inc.classpath.{ ClasspathFilter, ClasspathUtil } import sbt.internal.inc.classpath.{ ClasspathFilter, ClasspathUtil }
import sbt.internal.util.MessageOnlyException import sbt.internal.util.MessageOnlyException
@ -133,10 +133,17 @@ class Run(private[sbt] val newLoader: Seq[File] => ClassLoader, trapExit: Boolea
currentThread.setContextClassLoader(loader) currentThread.setContextClassLoader(loader)
try { try {
if (main.isStatic) { if (main.isStatic) {
if (Run.isJava25Plus) {
main.method.setAccessible(true)
}
if (main.parameterCount > 0) main.method.invoke(null, options.toArray[String]) if (main.parameterCount > 0) main.method.invoke(null, options.toArray[String])
else main.method.invoke(null) else main.method.invoke(null)
} else { } else {
val ref = main.mainClass.getDeclaredConstructor().newInstance().asInstanceOf[AnyRef] val constructor = main.mainClass.getDeclaredConstructor()
if (Run.isJava25Plus) {
constructor.setAccessible(true)
}
val ref = constructor.newInstance().asInstanceOf[AnyRef]
if (main.parameterCount > 0) main.method.invoke(ref, options.toArray[String]) if (main.parameterCount > 0) main.method.invoke(ref, options.toArray[String])
else main.method.invoke(ref) else main.method.invoke(ref)
} }
@ -165,10 +172,24 @@ class Run(private[sbt] val newLoader: Seq[File] => ClassLoader, trapExit: Boolea
val method = try { val method = try {
mainClass.getMethod("main", classOf[Array[String]]) mainClass.getMethod("main", classOf[Array[String]])
} catch { } catch {
case _: NoSuchMethodException => mainClass.getMethod("main") case _: NoSuchMethodException =>
try {
mainClass.getMethod("main")
} catch {
case _: NoSuchMethodException =>
try {
mainClass.getDeclaredMethod("main", classOf[Array[String]])
} catch {
case _: NoSuchMethodException =>
mainClass.getDeclaredMethod("main")
}
}
}
val modifiers = method.getModifiers
if (isPrivate(modifiers)) {
throw new NoSuchMethodException(s"${mainClassName}.main is private")
} }
method.setAccessible(true) method.setAccessible(true)
val modifiers = method.getModifiers
DetectedMain(mainClass, method, isStatic(modifiers), method.getParameterCount()) DetectedMain(mainClass, method, isStatic(modifiers), method.getParameterCount())
} else { } else {
val method = mainClass.getMethod("main", classOf[Array[String]]) val method = mainClass.getMethod("main", classOf[Array[String]])

View File

@ -0,0 +1,7 @@
package example;
class A {
void main() {
System.out.println("package private no args");
}
}

View File

@ -0,0 +1,7 @@
package example;
class A {
protected void main() {
System.out.println("protected no args");
}
}

View File

@ -0,0 +1,7 @@
package example;
class A {
void main(String[] args) {
System.out.println("package private with args");
}
}

View File

@ -0,0 +1,7 @@
package example;
class A {
private void main(String[] args) {
System.out.println("private");
}
}

View File

@ -0,0 +1,3 @@
void main() {
IO.println("compact source file with java.lang.IO");
}

View File

@ -1,11 +1,54 @@
// 2.12.x uses Zinc's compiler bridge
ThisBuild / scalaVersion := "2.12.20"
@transient @transient
lazy val check = taskKey[Unit]("") lazy val check = taskKey[Unit]("")
check := { lazy val common = Def.settings(
if (scala.util.Properties.isJavaAtLeast("25")) // 2.12.x uses Zinc's compiler bridge
(Compile / run).toTask(" ").value scalaVersion := "2.12.20",
else () )
}
// use `runMain` instead of `run` because discoveredMainClasses return empty
// if JEP-512 java main method
// TODO fix zinc
// https://github.com/sbt/sbt/issues/7384#issuecomment-3361020003
lazy val commonRunMainCheck = Def.settings(
check := {
if (scala.util.Properties.isJavaAtLeast("25")) {
(Compile / runMain).toTask(" example.A").value
} else ()
}
)
lazy val a1 = project
.settings(common)
.settings(
check := {
if (scala.util.Properties.isJavaAtLeast("25")) {
assert((Compile / discoveredMainClasses).value.size == 1)
(Compile / run).toTask(" ").value
} else ()
}
)
lazy val a2 = project.settings(common, commonRunMainCheck)
lazy val a3 = project.settings(common, commonRunMainCheck)
lazy val a4 = project.settings(common, commonRunMainCheck)
lazy val a5 = project.settings(
common,
check := {
if (scala.util.Properties.isJavaAtLeast("25")) {
(Compile / runMain).toTask(" example.A").value
} else {
sys.error("not jdk 25")
}
}
)
lazy val a6 = project.settings(
common,
check := {
if (scala.util.Properties.isJavaAtLeast("25")) {
(Compile / runMain).toTask(" A").value
} else ()
}
)

View File

@ -1,2 +1,7 @@
# > run # > run
> check > a1/check
> a2/check
> a3/check
> a4/check
-> a5/check
> a6/check