从 Scala 程序中查找 Scala 库的位置
Finding Scala libraries location from within Scala program
我正在尝试让一个 Scala 程序产生另一个 Scala 程序。我设法从 System.getProperty("java.home")
获得了 java
可执行文件,我从 System.getProperty("java.class.path")
(sbt-launcher.jar
位置)获得了一些路径,并且 ClassLoader
我得到了 project/target/scala-2.11/classes
目录.
但是,我还是无法运行。 JVM 抱怨它无法找到 Scala 库的 类:
Exception in thread "main" java.lang.NoClassDefFoundError: scala/concurrent/ExecutionContext
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
at java.lang.Class.getMethod0(Class.java:3018)
at java.lang.Class.getMethod(Class.java:1784)
at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526)
Caused by: java.lang.ClassNotFoundException: scala.concurrent.ExecutionContext
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 7 more
我正在寻找将这些文件添加到类路径的方法,但我希望它是可移植的。我不想在本地计算机上寻找硬编码 scala 位置之类的解决方案,也不想使用现有环境变量和参数之外的其他环境变量和参数。我也不想依赖 SBT 或 Activators 在用户环境中的存在。
由于父 JVM 进程可以使用它们,因此它们的位置必须存储在某个地方,如果您能帮助我找到该位置,我将不胜感激。
为了成功地从另一个 Scala 应用程序生成一个 Scala 应用程序,我必须解决我的代码中的几个问题:
1。正确 main
class:
object ChildApp extends App {
println("success")
}
要确保 ChildApp
可以由 Java 运行,它必须是 object
。 Scala 没有 static
的概念,但是对象方法(和 main 将)被编译成静态方法。
2。正确的 class 姓名:
虽然 ChildApp.getClass.getName
returns ChildApp$
,它指的是一个对象(这样我们就可以传递其他静态方法-only class)。 Java 期望在命令行中使用 $
- 在其他工作中,我必须在将尾部 $
传递到流程构建器之前将其删除。
3。完整 class 路径
我没有在 System.getPropertiy("java.class.path")
:
中找到所有使用过的 JAR
val pcp = System getPropertiy "java.class.path" split File.pathSeparator // sbt-launcher.jar only
我也没有在 SystemClassLoader
中找到它们:
val scp = ClassLoader.getSystemClassLoader.asInstanceOf[URLClassLoader].getURLs.map(_.toString) // same as above
我确实使用 Class' 资源从我的项目中找到了编译文件:
// format like jar:file:/(your-project/compiled.jar)!some/package/ChildApp.class
lazy val jarClassPathPattern = "jar:(file:)?([^!]+)!.+".r
// format like file:/(your-project/compiled/some/package/ChildApp).class
lazy val fileClassPathPattern = "file:(.+).class".r
val jcp = jarClassPathPattern.findFirstMatchIn(pathToClass) map { matcher =>
val jarDir = Paths get (matcher group 2) getParent()
s"${jarDir}/*"
} toSet
val fcp = fileClassPathPattern.findFirstMatchIn(pathToClass) map { matcher =>
val suffix = "/" + clazz.getName
val fullPath = matcher group 1
fullPath substring (0, fullPath.length - suffix.length)
} toList
最后我找到了所有这些依赖项的存储位置:
// use App class' ClassLoader instead of system one
val lcp = ChildApp.getClass.getClassLoader.asInstanceOf[URLClassLoader].getURLs.map(_.toString)
4。奖励 - JVM 参数和 java
位置
val jvmArgs = ManagementFactory.getRuntimeMXBean.getInputArguments.toList
lazy val javaHome = System getProperty "java.home"
lazy val java = Seq(
Paths.get(javaHome, "bin", "java"),
Paths.get(javaHome, "bin", "java.exe")
) filter (Files exists _) head
那么你就拥有了 ProcessBuilder
/ Process
:
所需的一切
val executable = java.toString
val arguments = jvmArgs ++ List("-cp", classPath, mainName) ++ mainClassArguments
PS。我检查了几次 - 那些 附加的 JAR 既没有使用 CLASSPATH
环境变量也没有使用 -cp
参数传递(sbt-launcher.jar
的 MANIFEST 文件没有'也有任何东西)。所以任何知道它们是如何通过的以及为什么我的解决方案实际有效的人,请解释一下。
我正在尝试让一个 Scala 程序产生另一个 Scala 程序。我设法从 System.getProperty("java.home")
获得了 java
可执行文件,我从 System.getProperty("java.class.path")
(sbt-launcher.jar
位置)获得了一些路径,并且 ClassLoader
我得到了 project/target/scala-2.11/classes
目录.
但是,我还是无法运行。 JVM 抱怨它无法找到 Scala 库的 类:
Exception in thread "main" java.lang.NoClassDefFoundError: scala/concurrent/ExecutionContext
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
at java.lang.Class.getMethod0(Class.java:3018)
at java.lang.Class.getMethod(Class.java:1784)
at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526)
Caused by: java.lang.ClassNotFoundException: scala.concurrent.ExecutionContext
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 7 more
我正在寻找将这些文件添加到类路径的方法,但我希望它是可移植的。我不想在本地计算机上寻找硬编码 scala 位置之类的解决方案,也不想使用现有环境变量和参数之外的其他环境变量和参数。我也不想依赖 SBT 或 Activators 在用户环境中的存在。
由于父 JVM 进程可以使用它们,因此它们的位置必须存储在某个地方,如果您能帮助我找到该位置,我将不胜感激。
为了成功地从另一个 Scala 应用程序生成一个 Scala 应用程序,我必须解决我的代码中的几个问题:
1。正确 main
class:
object ChildApp extends App {
println("success")
}
要确保 ChildApp
可以由 Java 运行,它必须是 object
。 Scala 没有 static
的概念,但是对象方法(和 main 将)被编译成静态方法。
2。正确的 class 姓名:
虽然 ChildApp.getClass.getName
returns ChildApp$
,它指的是一个对象(这样我们就可以传递其他静态方法-only class)。 Java 期望在命令行中使用 $
- 在其他工作中,我必须在将尾部 $
传递到流程构建器之前将其删除。
3。完整 class 路径
我没有在 System.getPropertiy("java.class.path")
:
val pcp = System getPropertiy "java.class.path" split File.pathSeparator // sbt-launcher.jar only
我也没有在 SystemClassLoader
中找到它们:
val scp = ClassLoader.getSystemClassLoader.asInstanceOf[URLClassLoader].getURLs.map(_.toString) // same as above
我确实使用 Class' 资源从我的项目中找到了编译文件:
// format like jar:file:/(your-project/compiled.jar)!some/package/ChildApp.class
lazy val jarClassPathPattern = "jar:(file:)?([^!]+)!.+".r
// format like file:/(your-project/compiled/some/package/ChildApp).class
lazy val fileClassPathPattern = "file:(.+).class".r
val jcp = jarClassPathPattern.findFirstMatchIn(pathToClass) map { matcher =>
val jarDir = Paths get (matcher group 2) getParent()
s"${jarDir}/*"
} toSet
val fcp = fileClassPathPattern.findFirstMatchIn(pathToClass) map { matcher =>
val suffix = "/" + clazz.getName
val fullPath = matcher group 1
fullPath substring (0, fullPath.length - suffix.length)
} toList
最后我找到了所有这些依赖项的存储位置:
// use App class' ClassLoader instead of system one
val lcp = ChildApp.getClass.getClassLoader.asInstanceOf[URLClassLoader].getURLs.map(_.toString)
4。奖励 - JVM 参数和 java
位置
val jvmArgs = ManagementFactory.getRuntimeMXBean.getInputArguments.toList
lazy val javaHome = System getProperty "java.home"
lazy val java = Seq(
Paths.get(javaHome, "bin", "java"),
Paths.get(javaHome, "bin", "java.exe")
) filter (Files exists _) head
那么你就拥有了 ProcessBuilder
/ Process
:
val executable = java.toString
val arguments = jvmArgs ++ List("-cp", classPath, mainName) ++ mainClassArguments
PS。我检查了几次 - 那些 附加的 JAR 既没有使用 CLASSPATH
环境变量也没有使用 -cp
参数传递(sbt-launcher.jar
的 MANIFEST 文件没有'也有任何东西)。所以任何知道它们是如何通过的以及为什么我的解决方案实际有效的人,请解释一下。