Scala, JDK 11 and JPMS

Then the Scala compiler won’t identify module problems at compile time, but that will not mean the problems are unresolvable.

You seem to have confused “the Scala compiler doesn’t identify module issues at compile time” with “Scala simply doesn’t work with JPMS at all”. The former is true, the latter is not.

2 Likes

In programming there is always a solution to any problem, the question is, how far one wants to go for it.

My original question was if anywhere are guidelines for finding how to work around issues one can get using JPMS in Scala applications. From there the discussion faded, due to additional questions by me - sorry for that.

But I hope you can confirm, too, that the current situation with Java interoperability beyond Java 8 is not quite satisfying and that this is not even a target in Scala 3, even years after JPMS was introduced.

As long as we execute Scala programs on the JRE we need to take runtime problems as well into account. Coding and compiling stuff is just one side of the coin.

Java after 8 and JPMS are a thing, even if we, or me, don’t like it, and we must find a way to work with it. But often I have the impression, that people of the Scala community response is slightly annoyed if they are asked about problems related to Java 9+ and I just don’t understand why. A bunch of Github issues and Stackoverflow articles are not useful documentation, especially not for beginners.

(Please don’t misunderstand my statement, I didn’t judge the way you responded to me, I am more than grateful that you take your time to try to help, day after day, as so many others do here.)

I know, but for me one of Scala’s USP is: Don’t panic, the Scala compiler has your back! :slight_smile:

I’ve just run current version of https://github.com/scalafx/scalafx-hello-world without problems under Ubuntu and Java 11:

java --version
openjdk 11.0.7 2020-04-14
OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.7+10)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.7+10, mixed mode)

It downloaded and used OpenJFX 14 as a dependency under Java 11 and the window with a styled word “ScalaFX” shows as expected.

For some reason SBT didn’t use --add-modules or other JPMS related switches. The command line SBT used to run the example was just using -classpath:

/usr/lib/jvm/adoptopenjdk-11-hotspot-amd64/bin/java -classpath /tmp/sbt_96f9d9ee/job-1/target/f527dcdf/45981425/scalafx-hello-world_2.13-14-R19.jar:/tmp/sbt_96f9d9ee/target/3be29489/2580ecdc/scala-library-2.13.2.jar:/tmp/sbt_96f9d9ee/target/52a708fa/9f34c840/scalafx_2.13-14-R19.jar:/tmp/sbt_96f9d9ee/target/895779cf/d2bb0048/javafx-base-14.0.1-linux.jar:/tmp/sbt_96f9d9ee/target/203f6638/801033d9/javafx-controls-14.0.1-linux.jar:/tmp/sbt_96f9d9ee/target/9752eeeb/06685b3d/javafx-fxml-14.0.1-linux.jar:/tmp/sbt_96f9d9ee/target/830ce1fa/0ac9fa17/javafx-graphics-14.0.1-linux.jar:/tmp/sbt_96f9d9ee/target/92b31ba3/4b4e6e15/javafx-media-14.0.1-linux.jar:/tmp/sbt_96f9d9ee/target/dbd1a50f/e5742b86/javafx-swing-14.0.1-linux.jar:/tmp/sbt_96f9d9ee/target/5b1fe36e/b7aedf40/javafx-web-14.0.1-linux.jar:/tmp/sbt_96f9d9ee/target/bf8b00d6/f40a418b/scala-reflect-2.13.2.jar:/tmp/sbt_96f9d9ee/target/a0573e5e/c33f033a/javafx-graphics-14.0.1.jar:/tmp/sbt_96f9d9ee/target/c22b10d8/2b313230/javafx-controls-14.0.1.jar:/tmp/sbt_96f9d9ee/target/8d27d0ad/545d5987/javafx-base-14.0.1.jar:/tmp/sbt_96f9d9ee/target/296c091a/f2382648/javafx-media-14.0.1.jar hello.ScalaFXHelloWorld
1 Like

I know about ScalaFX, but to me there are some issues:

  1. ScalaFX does not work well with FXML and the Scene Builder.
  2. Using ScalaFX applies the “Another wrapper will solve the problem.” pattern, which I try to avoid.
  3. ScalaFX is just another dependency; I believe we should reduce the number of dependencies in our software.
  4. I know about ScalaFXML, but I don’t know how well maintained it is, plus: 3).

Okay, so let’s remove ScalaFX from the equation. I’ve hacked some ideas together and arrived at a working solution. Setup is the same as it was, i.e OpenJDK 11, OpenJFX 14, Ubuntu and SBT.

In directory /tmp/javafx-in-scala I’ve created two files:

build.sbt:

name := "javafx-in-scala"

version := "0.1"

scalaVersion := "2.13.2"

scalacOptions ++= Seq("-unchecked", "-deprecation", "-Xcheckinit", "-encoding", "utf8", "-feature")

// Fork a new JVM for 'run' and 'test:run', to avoid JavaFX double initialization problems
fork := true

// Determine OS version of JavaFX binaries
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!")
}

// Add JavaFX dependencies
lazy val javaFXModules = Seq("base", "controls", "fxml", "graphics", "media", "swing", "web")
libraryDependencies ++= javaFXModules.map( m=>
  "org.openjfx" % s"javafx-$m" % "14.0.1" classifier osName
)

HelloWorld.scala

import javafx.application.Application
import javafx.event.ActionEvent
import javafx.scene.Scene
import javafx.scene.control.Button
import javafx.scene.layout.StackPane
import javafx.stage.Stage

// must have different name than launched Application subclass
object HelloWorldLauncher {
  def main(args: Array[String]): Unit = {
    new HelloWorld().mainForwarder(args)
  }
}

class HelloWorld extends Application {
  def mainForwarder(args: Array[String]): Unit = {
    Application.launch(args: _*)
  }

  override def start(primaryStage: Stage): Unit = {
    primaryStage.setTitle("Hello World!")
    val btn = new Button
    btn.setText("Say 'Hello World'")
    btn.setOnAction((_: ActionEvent) => {
      System.out.println("Hello World!")
    })
    val root = new StackPane
    root.getChildren.add(btn)
    primaryStage.setScene(new Scene(root, 300, 250))
    primaryStage.show()
  }
}

sbt run gives following output:

$ sbt run
Warning: a legacy coursier cache was found at /home/piotrek/.coursier/cache/v1 and is currently being used.

Support for that cache location will be removed in coursier 2.0.0 final, whose release is imminent.

Follow the instructions at
  https://github.com/coursier/cache-migration#cache-migration
in order to migrate your cache to the newer location.


[info] welcome to sbt 1.3.11 (AdoptOpenJDK Java 11.0.7)
[info] loading settings for project global-plugins from idea.sbt ...
[info] loading global plugins from /home/piotrek/.sbt/1.0/plugins
[info] loading project definition from /tmp/javafx-in-scala/project
[info] loading settings for project javafx-in-scala from build.sbt ...
[info] set current project to javafx-in-scala (in build file:/tmp/javafx-in-scala/)
[info] Compiling 1 Scala source to /tmp/javafx-in-scala/target/scala-2.13/classes ...
[info] running (fork) HelloWorldLauncher 
[info] Hello World!
[info] Hello World!
[info] Hello World!
[info] Hello World!
[info] Hello World!
[info] Hello World!
[info] Hello World!
[info] Hello World!
[info] Hello World!
[info] Hello World!
[success] Total time: 8 s, completed 30 maj 2020, 12:24:45

Hello World! lines shows after you click the Hello World button.

Once again SBT uses old (pre JPMS) -classpath switch instead of new (JPMS related) --add-modules and the likes.

3 Likes

I’m not involved with the planning for Scala 3 (except SIP stuff which this isn’t), so I don’t know about that part. Is there a GitHub - lampepfl/dotty-feature-requests: Historical feature requests. Please create new feature requests at https://github.com/lampepfl/dotty/discussions/new?category=feature-requests ticket?

I think there’s still a good chance that Support JEP-261 Module System · Issue #529 · scala/scala-dev · GitHub will progress in the 2.13.x series. I think one reason it hasn’t is that it hasn’t been a blocker for people — which is why I was so keen to discover if this was truly a blocker for you or not. But it’s certainly worth improving regardless.

I apologize if I came off as irritated.

Thanks @tarsa for the sample code — I think this will be helpful to future seekers (and perhaps to @dubaut too).

1 Like

If I am generating for distribution I might not want to build the application just for the platform I am building on, do you know how to tell sbt to build three versions, one for each plaform?

You can probably make multi module SBT project, where 3 modules exist specifically to handle each of the 3 platforms.

https://www.scala-sbt.org/1.x/docs/Multi-Project.html

Why not just build on Java 8 only? That’s what nearly everyone in Scala OSS does. It’s a bit hard to offer advice unless we know a little more about your motivation to do it some other way.

1 Like

Because the JVM ecosystem has progressed quite a lot since Java 8. And I don’t think that Scala wants to give up its Java interop possibilities. If this would be the case, I’d out of the game.

I honestly would hope Lightbend would have an official position about moving towards post-Java 8. But all I get to hear is “Please subscribe to our commercial support, than we can help.” Funny thing: Lightbend does not offer commercial support, if you not a key-player in the IT business; at least that was the last answer from Lightbend’s sales department.

After all, it is usually us developers who convince companies to adopt Scala.

@SethTisue I am sorry if my post sounds harsh and it is not against you personally. But I am just fed up on how this topic is treated by Lightbend.

@SethTisue Don’t mean to be pushy but I agree with @dubaut. Some libraries simply won’t work with older versions of the JDK or if they do we have to use older versions that are not maintained.

1 Like

Scala works on Java 9+. It’s “just” the module system support that is missing. But that shouldn’t block you from using new functionalities from Java 9+.

Is there any need to switch to modules when migrating past Java 8? No. Mark Reinhold on July 17, 2020 (Mark Rheinold is chief architect of Java https://twitter.com/mreinhold/status/1284181068145295362).

No.

There is no need to switch to modules.

There has never been a need to switch to modules.

Java 9 and later releases support traditional JAR files on the traditional class path, via the concept of the unnamed module, and will likely do so until the heat death of the universe.

Whether to start using modules is entirely up to you.

1 Like

First of all, Java 9+ is officially not supported by Scala and this means that enterprise-level applications should not use Java 9+.

Secondly, if libraries decide to adopt the module system, you will have a hard time using them. Please remember my original questions. All I got here were workarounds. No solid solutions to my problem.

1 Like

Your original question was whether there were any comprehensive tutorials. The answer was no.

That’s a sucky answer, so a lot of people are trying to help you with your actual use case, regardless of your original question. Don’t make this about people dancing around your original question which was answered quickly and fully.

What you got are workarounds because the answer to your original question is clear but unfortunate.

1 Like

Following table suggests that running Scala under Java 9+ is supported: JDK Compatibility | Scala Documentation

Yes, integrating JPMS with Scala is hard and unsupported. However that doesn’t block anyone from using JARs (including JARs that require Java 9+) and newest additions to Java 9+ standard library. In fact my SBT/ Scala example above uses JARs with OpenJFX 14 that require Java 11+ and it’s running fine.

So to recap: Scala is officially compatible with Java 9+ as long as you don’t use JPMS.

2 Likes

I know that I got workarounds and I have to use one of them. However, this is not a satisfactory situation. All we get when asking for Java 9+ support its annoyed responses. Apparently this is an open wound for whatever reason.

I am not sure where you gathering this. As far as I understand this table, it his recommended to use JDK 8 and everything else has experimental support by the Scala compiler. Who can effort experiments when building enterprise-level software? This page contains lot of perhapses and maybes.

I am not sure why you so strongly try to defend this path of action by the developers of Scala. This cannot be an acceptable situation for them, either. What I would expect the least is an official position on all these topics. And it is not only me who’s requesting those features here. It comes up several times when talking to companies you want to convince to adopt Scala. They ask for support and I get the impression that neither the community nor Lightbehd is interested in supporting them.

I have not defended anything. I just don’t understand why you consider Java 11 unsupported by Scala.

No, the article says JDK 8 and JDK 11 are supported except for JPMS.

Support for non-LTS versions of Java is experimental though, but such Java versions aren’t recommended for production usage unless you are willing to upgrade Java versions regularly. Java 9, Java 10, Java 12 and Java 13 are already EOL’d. The only non-LTS Java version that is supported by Oracle is Java 14, but it will be EOL’d this month when Java 15 comes out. It makes IMO little sense to support Java versions already abandoned by Oracle.

3 Likes

Yeah, this. It’s true that JDK 11 was considered experimental for a while, but it’s been officially supported for quite some time now. It doesn’t use all the features of JDK 11, but that’s by no means the same thing as saying that it’s unsupported…

3 Likes