你如何 specify/figure 找出 运行 脂肪罐需要哪个最小值 JDK?

How do you specify/figure out which minimum JDK is required for running the fat jar?

我在一个项目中使用了 sbt-assembly,我有一些 java 14 个 jar,而我的本地机器默认有 JDK 8 个 JDK。

sbt assembly任务成功,生成了一个fat jar。

当我 运行 它与 JDK 8 时,我得到错误:

Exception in thread "main" java.lang.UnsupportedClassVersionError: javafx/event/EventTarget has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0

JDK11(55.0版)是我需要的。果然,当我在 shell 上设置 JDK 11 时,我可以 运行 fat jar.

有没有办法明确 build.sbt 文件中的目标 JDK 版本? 另外,令我惊讶的是,即使我在依赖项中有 Java 14 个 jar,应用程序 运行 在 JDK 11 上也很好。它只是 Java 的一个例子吗的最高向后兼容性在行动?我想知道还有什么可以在工作。

这就是我的 build.sbt 的样子

name := "scalafx-app"

version := "0.1"

scalaVersion := "2.13.3"

scalacOptions += "-Ymacro-annotations"

useCoursier := false
assemblyMergeStrategy in assembly := {
  case "module-info.class" => MergeStrategy.concat
  case x =>
    val oldStrategy = (assemblyMergeStrategy in assembly).value
    oldStrategy(x)
}
lazy val scalaTest = "org.scalatest" %% "scalatest" % "3.1.1"

lazy val osName = System.getProperty("os.name") match {
  case n if n.startsWith("Linux") => "linux"
  case n if n.startsWith("Mac") => "mac"
  case n if n.startsWith("Windows") => "win"
  case _ => throw new Exception("Unknown platform!")
}

lazy val javaFXModules = Seq("base", "controls", "fxml", "graphics", "media", "web")


lazy val root = (project in file("."))
  .settings(
    libraryDependencies += scalaTest % Test,

    // scalafx
    libraryDependencies += "org.scalafx" %% "scalafx" % "14-R19",
    libraryDependencies ++= javaFXModules.map(m =>
      "org.openjfx" % s"javafx-$m" % "14.0.1" classifier(osName) withJavadoc()
    ),
    libraryDependencies += "org.scalafx" %% "scalafxml-core-sfx8" % "0.5",

    // javafx custom components
    libraryDependencies += "com.jfoenix" % "jfoenix" % "9.0.9",
    libraryDependencies += "org.kordamp.ikonli" % "ikonli-javafx" % "11.4.0",
    libraryDependencies += "org.kordamp.ikonli" % "ikonli-material-pack" % "11.4.0",

    // json parsing
    libraryDependencies += "com.typesafe.play" %% "play-json" % "2.9.0",
    libraryDependencies += "com.squareup.moshi" % "moshi" % "1.9.3",

      // logging
    libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.9.2",
    libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.2.3",

  )

A JAR 就像 classes 的 zip,每个 class 都是你可以用 javap 检查的那个通过查看 "主要版本" 字段的值,查看他们需要哪个 JDK 版本;参见 this

如果你想确保 classes 被编译成特定的 Java 版本,你可以使用 release & target scalac options.

像这样:

// Ensure the compiler emits Java 8 bytecode.
scalacOptions ++= Seq("-release", "8", "-target:8")
  • release用于指定使用哪个Javasdtlib
  • target 用于指定发出哪个 bytcode 版本。